2009-10-25 4 views
0

J'ai un problème JavaScript insidieux avec lequel j'ai besoin d'aide. Je génère du code HTML à partir d'une structure JSON. L'idée est que je devrais être en mesure de passer une liste comme:Pourquoi cette fonction fonctionne-t-elle pour les littéraux mais pas pour les expressions plus complexes?

['b',{'class':'${class_name}'}, ['i', {}, 'Some text goes here']] 

... et obtenir (si class_name = 'foo') ...

<b class='foo'><i>Some text goes here.</i></b> 

J'utilise les fonctions suivantes:

function replaceVariableSequences(str, vars) { 
    /* @TODO Compiling two regexes is probably suboptimal. */ 
    var patIdent = /(\$\{\w+\})/; // For identification. 
    var patExtr = /\$\{(\w+)\}/; // For extraction. 

    var pieces = str.split(patIdent); 

    for(var i = 0; i < pieces.length; i++) { 
     if (matches = pieces[i].match(patExtr)) { 
      pieces[i] = vars[matches[1]]; 
     } 
    } 

    return pieces.join(''); 
} 

function renderLogicalElement(vars, doc) { 
    if (typeof(doc[0]) == 'string') { 

     /* Arg represents an element. */ 

     /* First, perform variable substitution on the attribute values. */ 
     if (doc[1] != {}) { 
      for(var i in doc[1]) { 
       doc[1][i] = replaceVariableSequences(doc[1][i], vars); 
      } 
     } 

     /* Create element and store in a placeholder variable so you can 
      append text or nodes later. */ 

     var elementToReturn = createDOM(doc[0], doc[1]); 

    } else if (isArrayLike(doc[0])) { 

     /* Arg is a list of elements. */ 
     return map(partial(renderLogicalElement, vars), doc); 

    } 

    if (typeof(doc[2]) == 'string') { 

     /* Arg is literal text used as innerHTML. */ 
     elementToReturn.innerHTML = doc[2]; 

    } else if (isArrayLike(doc[2])) { 

     /* Arg either (a) represents an element 
        or (b) represents a list of elements. */ 
     appendChildNodes(elementToReturn, renderLogicalElement(vars, doc[2])); 

    } 

    return elementToReturn; 
} 

Cela fonctionne magnifiquement parfois, mais pas d'autres. Exemple du code d'appel:

/* Correct; Works as expected. */ 
var siblings = findChildElements($('kv_body'), ['tr']); 
var new_id = 4; 

appendChildNodes($('kv_body'), 
       renderLogicalElement({'id': new_id}, 
             templates['kveKeyValue'])); 




/* Incorrect; Substitutes "0" for the expression instead of the value of 
    `siblings.length` . */ 
var siblings = findChildElements($('kv_body'), ['tr']); 
var new_id = siblings.length; // Notice change here! 

appendChildNodes($('kv_body'), 
       renderLogicalElement({'id': new_id}, 
             templates['kveKeyValue'])); 

Quand je piège le premier argument de renderLogicalElement() utilisant alert(), je vois un zéro. Pourquoi est-ce?? J'ai l'impression que c'est quelque chose de type JavaScript, possiblement lié aux littéraux d'objets, que je ne connais pas.

Modifier: J'ai ce code connecté à l'événement de clic pour un bouton sur ma page. Chaque clic ajoute une nouvelle ligne à l'élément <tbody> dont l'ID est kv_body. La première fois que cette fonction est appelée, siblings est en effet zéro. Cependant, une fois que nous ajoutons un <tr> au mélange, siblings.length évalue au nombre approprié, augmentant chaque fois que nous ajoutons un <tr>. Désolé de ne pas être plus clair !! :)

Merci d'avance pour tout conseil que vous pouvez donner.

Répondre

0

Si new_id est 0, cela ne signifie-t-il pas que siblings.length est 0? Peut-être qu'il n'y a vraiment aucun frère.

0

Peut-être que siblings.length est actuellement 0? Essayez de déboguer davantage (par exemple avec Firebug)

0

OK, je l'ai corrigé. Comme il s'avère, je modifiais mon objet JSON source avec le premier appel de fonction (parce que dans JS vous êtes simplement en train de passer des pointeurs). J'avais besoin d'écrire une fonction de copie qui ferait une nouvelle copie des données pertinentes.

http://my.opera.com/GreyWyvern/blog/show.dml/1725165

J'ai fini par retirer ce en fonction de prototype et juste faire une fonction régulière ancienne.

Questions connexes