2013-04-19 15 views
11

Ho un oggetto master nel mio setup JS, cioè .:Come associare un oggetto con un DOM elemento

var myGarage = { 
    cars: [ 
     { 
      make: "Ford", 
      model: "Escape", 
      color: "Green", 
      inuse: false 
     }, 
     { 
      make: "Dodge", 
      model: "Viper" 
      color: "Red", 
      inuse: true 
     }, 
     { 
      make: "Toyota", 
      model: "Camry" 
      color: "Blue", 
      inuse: false 
     } 
    ] 
} 

Ora ho un ciclo sulle mie macchine e metterle in una tabella. Nella tabella ho anche un pulsante che mi permette di attivare la macchina come "in uso" e "non in uso".

Come posso associare l'elemento DOM di ogni riga con la relativa auto, in modo che se si attiva il flag "in uso", posso aggiornare l'oggetto master?

+0

Avete preso in considerazione il metodo '.data()' di jQuery? – Barmar

+0

L'ho fatto, ma come posso memorizzare un riferimento a ciascun oggetto auto all'interno? – Steve

+0

Qualcosa come '$ (" ") .data (auto) .appendTo (tabella)' – Barmar

risposta

7

Suggerirei di considerare addEventListener e un costruttore che conforma gli oggetti all'interfaccia eventListener.

In questo modo puoi avere una buona associazione tra il tuo oggetto, il tuo elemento e i suoi gestori.

Per fare ciò, creare un costruttore specifico per i dati.

function Car(props) { 
    this.make = props.make; 
    this.model = props.model; 
    // and so on... 

    this.element = document.createElement("div"); // or whatever 

    document.body.appendChild(this.element);  // or whatever 

    this.element.addEventListener("click", this, false); 
} 

quindi implementare l'interfaccia:

Car.prototype.handleEvent = function(e) { 
    switch (e.type) { 
     case "click": this.click(e); 
     // add other event types if needed 
    } 
} 

quindi implementare la tua .click() gestore sul prototipo.

Car.prototype.click = function(e) { 
    // do something with this.element... 
    this.element.style.color = "#F00"; 

    // ...and the other properties 
    this.inuse = !this.inuse 
} 

Così allora si può solo ciclo sopra l'Array, e fare una nuova Car oggetto per ogni elemento, e si metterà a creare il nuovo elemento e aggiungere l'ascoltatore (s).

myGarage.cars.forEach(function(obj) { 
    new Car(obj) 
}) 
+0

ha detto che sta usando jQuery, quindi ognuno di questi può essere abbreviato in one-liner. – Barmar

+0

Grazie mille per la spiegazione dettagliata. In realtà lo sto facendo molto simile a questo. La descrizione precedente era solo una spiegazione più breve per impostare il mio problema reale: Come immagazzino un riferimento a ciascun oggetto auto (all'interno dell'oggetto myGarage) all'interno dell'elemento riga 'tr', in modo da poter aggiornare facilmente l'oggetto originale all'interno di un clic handler. – Steve

+0

@Barmar: Forse mi manca, ma non vedo dove si dice "usando jQuery". Vedo il tag, ma è tutto. –

0

Avrai bisogno di qualche tipo di ID o riga distinta nelle tue informazioni, altrimenti dovrai fare affidamento sull'indice dell'array per farlo. In entrambi i casi, vorrai memorizzare i dati usando data attributes.

Quindi, quando si esegue un ciclo:

for (var i = 0, l = array.length; i < l; i++) { 
    var div = '<tr data-car="' + JSON.stringify(array[i]) + '" data-index="' + i + '"><td></td></tr>' 
} 

E sul vostro evento click:

$('button').click(function() { 
    var carIndex = $(this).closest('tr').attr('data-index'); 
    var carData = $(this).closest('tr').attr('data-car'); 
    if (carData) carData = JSON.parse(carData); 

    myGarage.cars[carIndex].inUse = true; 
}) 

Se si associa i dati al DOM, si può anche non essere necessario aggiornare i dati effettivi JS . Potrebbe passare sopra ogni riga della tabella e ricreare l'oggetto dati da cui hai creato la tabella.

+0

Il problema con questo approccio è che io memorizzo una copia di ogni oggetto dell'automobile in 'data-attribute'. Non è quello che voglio. Voglio un riferimento all'oggetto originale nell'oggetto master. – Steve

+0

Quindi memorizzare l'indice solo utilizzando gli attributi dei dati? Non esiste un modo sicuro per ottenere un riferimento a un elemento DOM. Se dovessi trovarlo con jQuery e salvarlo sull'oggetto della tua auto, il riferimento jQuery non verrà impostato in modo affidabile. Potrebbe essere possibile memorizzare l'elemento della tabella non formattato (document.getElementById ad esempio) nell'oggetto principale myGarage, tuttavia è necessario testare il riferimento tra le chiamate di funzione. –

+0

Perché stiamo aggiungendo carIndex alla riga ... Perché non aggiungerlo sul pulsante stesso. Mi salverà una query DOM per trovare la riga più vicina. La mia risposta fa lo stesso. Fammi sapere se c'è una ragione per questo. – sachinjain024

14

Si può effettivamente collegare un oggetto direttamente a un nodo:

var n = document.getElementById('green-ford-escape'); 
n.carObject = myGarage.cars[0]; 
n.onclick = function() { 
    doSomethingWith(this.carObject); 
} 

Per lo stesso di rimuovere l'ambiguità, in alcuni casi, è più chiaro scrivere il gestore di eventi di cui sopra per fare riferimento a n invece di this:

n.onclick = function() { 
    doSomethingWith(n.carObject); 
} 

È inoltre possibile fare riferimento direttamente all'oggetto dall'evento allegato:

var n = document.getElementById('green-ford-escape'); 
n.onclick = function() { 
    doSomethingWith(myGarage.cars[0]); 
} 

In questo caso, myGarage non non devono essere globali. Si può fare questo e si aspettano di funzionare correttamente:

(function(){ 

    var myGarage = { /* ... etc ... */ }; 

    var n = document.getElementById('green-ford-escape'); 
    n.onclick = function() { 
     doSomethingWith(myGarage.cars[0]); 
    } 

})(); 

evento funzione del nodo "tenere su" la variabile locale in modo corretto, creando di fatto una variabile privata.

È possibile verificare questo nel vostro/FF console Cromo/IE:

var o = {a: 1}; 
var n = document.createElement('div'); 
n.innerHTML = "click me"; 
n.data = o; 
n.onclick = function() { n.data.a++; console.log(n.data, o); } 
document.body.appendChild(n); 

Si dovrebbe vedere il log della console due oggetti identici con ogni clic, ciascuna con incremento a valori.

Beware l'impostazione di n.data su una primitiva non crea un riferimento. Copierà il valore.

+0

Dolce ... questo è quello che stavo cercando. Quindi è del tutto OK memorizzare un riferimento all'oggetto nidificato collegato a DOMElement? – Steve

+0

@Steve Ultimamente non ho controllato le specifiche. E sospetto che il riferimento all'oggetto nel gestore di eventi sia meno "pericoloso" nella mente di alcune persone. Tuttavia, il collegamento dell'oggetto direttamente al nodo * funzionerà *. Basta osservare le collisioni con gli attributi incorporati - penso che le specifiche suggeriscano il prefisso di tutti gli attributi personalizzati con 'x-vendorname-' o 'data-'. ('x-vendor' potrebbe essere la raccomandazione per i programmi utente.) – svidgen

+0

Attenzione che estendere gli oggetti DOM in questo modo è sicuro solo negli ambienti controllati. Ecco un grande articolo di kangax: http: // perfectionkills.it/whats-wrong-with-extending-the-dom/# lack_of_specification. – tomekwi

0

È possibile utilizzare l'attributo data- * HTML5 per individuare la riga corrispondente. È necessario fare qualcosa di simile

var table = $('<table>'); // Let's create a new table even if we have an empty table in our DOM. Simple reason: we will achieve single DOM operation (Faster) 

for (var i=0; i<myGarbage.cars.length; i++) { 
    // Create a new row and append to table 
    var tr = $('<tr>').appendTo(table); 

    var carObject = myGarbage.cars[i]; 
    // Traverse the JSON object for each car 
    for (var key in carObject) { 
     // Create other cells. I am doing the last one 
     var td = $('<td>').appendTo(tr); 
     var button = $('<button>').attr('data-carId', i).addClass('toggle-inuse').appendTo(td); 
    } 
} 
// If en ampty table awaits me in DOM 
$('#tableId').html(table.html()); 

Ora si aggiunge listener di eventi sul tasto: -

$('.toggle-inuse').click(function() { 
    var i = $(this).data('carId'); 
    myGarbage.cars[i].inuse = !myGarbage.cars[i].inuse; //Wow done 
} 

provare questo fuori !!

Problemi correlati