11528 sujets

JavaScript, DOM et API Web HTML5

Bonjour, actuellement je cherche à créer et insérer plusieurs éléments HTML au check d'un bouton radio.
J'ai une première version de ma fonction qui marche mais qui se répète beaucoup, j'aimerais factoriser ce code (dans une boucle for par exemple).

Extrait du code HTML concerné:

<input type="checkbox" class="custom-control-input" id="customCheck1" onclick="editerPage()">


Extrait de la fonction qui marche mais qui contient du code répété:

function editerPage() {
    var boutonTitre = document.createElement('button');
    boutonTitre.id = 'titre';
    boutonTitre.innerHTML = 'Titre de l\'onglet de la page';
    boutonTitre.setAttribute('onclick', 'titre()');
    var boutonH1 = document.createElement('button');
    boutonH1.id = 'h1';
    boutonH1.innerHTML = 'Titre h1 de la page';
    boutonH1.setAttribute('onclick', 'h1()');
    var boutonP = document.createElement('button');
    boutonP.innerHTML = 'Paragraphe de la page';
    boutonP.id = 'p';
    boutonP.setAttribute('onclick', 'p()');
    var inputCouleurH1 = document.createElement('input');
    inputCouleurH1.innerHTML = 'Changer la couleur du titre h1';
    inputCouleurH1.id = 'input';
    inputCouleurH1.setAttribute('onclick', 'couleurH1()');
    inputCouleurH1.setAttribute('type', 'color');
    document.body.appendChild(boutonTitre);
    document.body.appendChild(boutonH1);
    document.body.appendChild(boutonP);
    document.body.appendChild(inputCouleurH1);
}


Déclaration du tableau dans lequel j'ai les éléments sur lesquel je souhaite boucler + Tentative d'une fonction avec boucle for qui ne fonctionne pas (pas de message dans la console rien):

var bouton = ['title', 'h1', 'p', 'input']

function editerPage() {
    for ( i = 0; i >= bouton.length; i++ ) {
        bouton[i] = document.createElement('button');
        bouton[i].innerHTML = 'Création du ' + bouton[i];
        bouton[i].id = '"' + bouton[i] + '"';
        bouton[i].setAttribute('onclick', '"' + bouton[i] + '"');
        document.body.appendChild(bouton[i]);
    }
}


Une idée svp?
J'imagine que la solution est évidente... En tout cas pas pour moi ;D.
Je remercie d'avance ceux qui voudrons bien m'aider.
Modifié par Knhfr (07 Aug 2020 - 21:15)
Finalement j'ai fait comme ça:

function editerPage() {
    let div = document.createElement('div');
    div.id = 'div';
    document.body.appendChild(div);
    var bouton = document.createElement('button');
    bouton.innerHTML = 'Valider';
    bouton.setAttribute('onclick', 'editerElement()');
    let attributes = {
        type: ['input', 'input', 'input', 'input'],
        id: ['Titre', 'H1', 'CouleurH1', 'P'],
        placeholder: ['Titre de l\'onglet de la page', 'Titre h1 de la page', 'Changer la couleur du titre h1', 'Paragraphe de la page'],
        click: ['titre()', 'h1()', 'couleurH1()', 'p()'],
        class: ['col-6', 'col-6', 'col-2', 'col-6']
    };
    for (let i = 0; i < 4; i++ ){
        var divElement = document.createElement('div');
        // div.classList.add('div' + attributes.id);
        // var bouton = document.createElement('button');
        // bouton.innerHTML = 'Valider';
        // bouton.setAttribute('onclick', attributes.click);
        var element = document.createElement(attributes.type[i]);
        element.id = 'input' + attributes.id[i];
        element.setAttribute('placeholder', attributes.placeholder[i]);
        element.classList.add(attributes.class[i]);
        if ('inputCouleurH1' === 'input' + attributes.id[i]) {
            element.setAttribute('type', 'color');
            var label = document.createElement('label');
            label.classList.add('col-4');
            label.innerHTML = 'Changer la couleur du h1';
            divElement.appendChild(label);
        }
        div.appendChild(divElement);
        // divElement.appendChild(bouton);
        divElement.appendChild(element);
    }
    divElement.appendChild(bouton);
    document.getElementById('customCheck1').setAttribute('onclick', 'editerPageOff()')
}
Salut,

Ton réflexe de vouloir factoriser ton code est une très bonne chose ! Smiley smile Cependant, il existe des techniques simples et efficaces qui permettent d'éviter les répétitions tout en clarifiant le code. Dans ta solution, tu évites effectivement les répétitions, mais ton code reste en un seul bloc. Découper son code permet de le rendre plus clair et plus simple. Cela empêche également d'ajouter des bugs lors de changements futurs. Chaque partie étant indépendante, cela limite les effets de bord.

La première chose à faire lorsque l'on veut factoriser son code est de le découper en fonctions :

function addButton(id, text, action) {
  const button = document.createElement('button')
  button.id = id
  button.innerHTML = text
  button.setAttribute('onclick', action)
  document.body.appendChild(button)
}

function addColorButton(id, text, action) {
  const button = document.createElement('input')
  button.setAttribute('type', 'color')
  button.id = id
  button.innerHTML = text
  button.setAttribute('onclick', action)
  document.body.appendChild(button)
}

function editerPage() {
  addButton('titre', 'Titre de l\'onglet de la page', 'titre()')
  addButton('h1', 'Titre h1 de la page', 'h1()')
  addButton('p', 'Paragraphe de la page', 'p()')
  addColorButton('input', 'Changer la couleur du titre h1', 'couleurH1()')
}

editerPage()

Ensuite on voit ce qu'on peut regrouper :

function addAttributes(element, id, text, action) {
  element.id = id
  element.innerHTML = text
  element.setAttribute('onclick', action)
  document.body.appendChild(element)
}

function addButton(id, text, action) {
  const button = document.createElement('button')
  addAttributes(button, id, text, action)
}

function addColorButton(id, text, action) {
  const button = document.createElement('input')
  button.setAttribute('type', 'color')
  addAttributes(button, id, text, action)
}

Idéalement, une fonction devrait avoir un minimum d'arguments pour rester facilement compréhensible. On peut donc regrouper la liste d'attributs dans une classe :


class AttributeList {
  constructor(id, text, action) {
    this.id = id
    this.text = text
    this.action = action
  }
}

function addAttributes(element, attributes) {
  element.id = attributes.id
  element.innerHTML = attributes.text
  element.setAttribute('onclick', attributes.action)
  document.body.appendChild(element)
}

function addButton(attributes) {
  const button = document.createElement('button')
  addAttributes(button, attributes)
}

function addColorButton(attributes) {
  const button = document.createElement('input')
  button.setAttribute('type', 'color')
  addAttributes(button, attributes)
}

function editerPage() {
  addButton(new AttributeList('titre', 'Titre de l\'onglet de la page', 'titre()'))
  addButton(new AttributeList('h1', 'Titre h1 de la page', 'h1()'))
  addButton(new AttributeList('p', 'Paragraphe de la page', 'p()'))
  addColorButton(new AttributeList('input', 'Changer la couleur du titre h1', 'couleurH1()'))
}

editerPage()

On peut séparer les données des fonctions et utiliser une boucle pour éviter de répéter l'appel à addButton :

function editerPage() {
  const elements = {
    buttons: [
      new AttributeList('titre', 'Titre de l\'onglet de la page', 'titre()'),
      new AttributeList('h1', 'Titre h1 de la page', 'h1()'),
      new AttributeList('p', 'Paragraphe de la page', 'p()')
    ],
    colorButtons: [
      new AttributeList('input', 'Changer la couleur du titre h1', 'couleurH1()')
    ]
  }
  
  elements.buttons.forEach(attributes => addButton(attributes))
  elements.colorButtons.forEach(attributes => addColorButton(attributes))
}

Enfin, on peut regrouper les fonctions dans des classes afin d'avoir un code plus facilement corrigeable et évolutif :


class AttributeList {
  constructor(id, text, action) {
    this.id = id
    this.text = text
    this.action = action
  }
}

class Element {
  constructor(attributes) {
    this.element = this.createElement()
    this.addAttributes(attributes)
    document.body.appendChild(this.element)
  }
  
  addAttributes(attributes) {
    this.element.id = attributes.id
    this.element.innerHTML = attributes.text
    this.element.setAttribute('onclick', attributes.action)
  }
}

class Button extends Element {
  createElement() {
    return document.createElement('button')
  }
}

class ColorButton extends Element {
  createElement() {
    const button = document.createElement('input')
    button.setAttribute('type', 'color')
    return button
  }
}


function createButtons(buttons) {
  buttons.forEach(attributes => new Button(attributes))
}

function createColorButtons(buttons) {
  buttons.forEach(attributes => new ColorButton(attributes))
}

function editerPage() {
  const elements = {
    buttons: [
      new AttributeList('titre', 'Titre de l\'onglet de la page', 'titre()'),
      new AttributeList('h1', 'Titre h1 de la page', 'h1()'),
      new AttributeList('p', 'Paragraphe de la page', 'p()')
    ],
    colorButtons: [
      new AttributeList('input', 'Changer la couleur du titre h1', 'couleurH1()')
    ]
  }
  
  createButtons(elements.buttons)
  createColorButtons(elements.colorButtons)
}

editerPage()

Ça a l'air super !
Je dois prendre le temps de tout décortiquer pour le comprendre et pouvoir le refaire Smiley smile . Je vois ça demain ou lundi. Merci beaucoup !!