2013-01-16 2 views
6

Diciamo che ho un arco legatoCome ottenere l'espressione vincolante all'interno di una BindingHandler in Knockout JS

<span data-bind="MyBinding: Name"></span> 

e ho un legame

ko.bindingHandlers.MyBinding = { 
    init: function (element, valueAccessor, allBindings, viewModel, context) { 
     // I want to get the string "Name" here. NOT the value of Name. 
    }, 
}; 

Come faccio ad avere una stringa con il costume valore dell'espressione di legame all'interno del gestore? cioè come ottengo "Nome" non "Valore del nome".

Ho anche bisogno dell'espressione in modo che passare la stringa "Nome" non sia fattibile.

<span data-bind="MyBinding: 'Name'"></span> 

risposta

2

In realtà, il knockout fa ha un modo integrato per farlo. È necessario adattare un po 'il binding personalizzato (vale a dire, diventa un oggetto invece di un valore stringa). Knockout ti consente, insieme alle proprietà init e update, di specificare una proprietà preprocess. Ad esempio, supponiamo di avere la seguente ViewModel:

var app = { data: ko.observable('Hello World') }; 

E un semplice legame che convertire la stringa passata ad esso completamente in minuscolo, e l'uscita sia il nome e il valore del legame (la proprietà passò nella vista, ovviamente, essendo data):

ko.bindingHandlers.lower = { 
    update: function(elem, value) { 
    var obj = ko.unwrap(value()); 
    elem.textContent = 'Name: ' + ko.unwrap(obj.name) + 
     ' - Value: ' + ko.unwrap(obj.data).toLowerCase(); 
    }, 
    preprocess: function(value, bindingName) { 
    return '{data:' + value + ', name:\'' + bindingName + '\'}'; 
    } 
}; 

è semplice come stringifying proprietà value passata ad esso & trasformare il valore di binding in un oggetto con 2 chiavi (nome & valore qui). Have a look. Vedi Binding preprocessing per maggiori informazioni.

2

è necessario passare in Name come stringa e non come punto di riferimento:

<span data-bind="MyBinding: 'Name'"></span> 

ko.bindingHandlers.MyBinding = { 
    init: function (element, valueAccessor, allBindings, viewModel, context) { 
     var myBinding = valueAccessor(); // will contain 'Name'; 
     var valueOfmyBinding = viewModel[myBinding]; //value of the Name property 
    }, 
}; 

si può ancora usare la tua espressione come una stringa, perché in JavaScript è possibile eval benche eval() è una funzione pericolosa: Ecco un esempio JSFiddle.

Oppure, se è sufficiente supportare un'espressione di proprietà semplice come Child.Name, è possibile scrivere il proprio parser in cui si divide la stringa sui punti e si predispone sugli accessori.

+0

Come funzionerà se si tratta di un'espressione complessa. es. "Child.Name" – Simon

+0

Perché la stringa non funzionerà per te? In JavaScript puoi "evalare" praticamente qualsiasi stringa nel codice JS. – nemesv

+0

Ovviamente. fammi provare. – Simon

1

Si potrebbe fare quanto segue, quindi non sarà necessario l'eval.

<span data-bind="MyBinding: 'Name.More.AndMore'"></span> 

ko.bindingHandlers.MyBinding = { 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
     var value = valueAccessor(); 

     var sp = value.split('.'); 
     var current = viewModel; 
     for(var i=0;i<sp.length;i++) { 
      var nNode = current[sp[i]]; 
      if (nNode) { 
       current = nNode; 
      } 
     } 
     $(element).html(current()); 
    } 
}; 

Come già spiegato, è necessario dare il nome come valore stringa nel vostro legame. Successivamente è possibile utilizzare questo per scorrere il tuo viewmodel per recuperare il valore. Per visualizzare il valore nell'elemento che ho aggiunto $(element).html(current()); Qui lo current() è al livello più profondo nel mio viewmodel quindi può essere chiamato e il valore di ritorno può essere utilizzato per aggiornare l'html.

+0

Puoi descrivere cosa è "il seguente"? Perché risponde alla domanda? Puoi [modificare] la tua risposta per includere una descrizione. –

+0

Ho appena ampliato la risposta che @nemesv ha dato. Con il seguito intendo il seguente pezzo di codice – gkempkens

0

Sono un po 'in ritardo alla festa su questo, ma ecco quello che ho fatto, e funziona come un fascino:

JS:

ko.bindingHandlers.myHandler = { 
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     var regex = /return ([^\s]+)\s*}/; 

     //accessor will contain whatever expression was used in data-bind 
     //so in this example it will be "myProp.childProp" 
     var accessor = regex.exec(valueAccessor.toString())[1]; 

     //... 
}, 
//... 

HTML:

<div data-bind="myHandler: myProp.childProp"></div> 

Quindi il valore dell'accessorio (nel caso in cui abbiate perso il commento) sarà "myProp.childProp"

1

Propongo di trasferire il nome del pro perty con uso un altro legame.

<div data-bind="myBinding: content, nameOfProp:'content'"></div> 

ko.bindingHandlers.myBinding = { 
    init: function(element, valueAccessor, allBindings, viewModel, context) { 
     var nameOfProp = allBindings.get("nameOfProp"); 
    }; 
    } 

JSFiddle

1

mi piace quello che ha detto Pavel-chervov sopra. Allo stesso modo se non ti dispiace usare un po 'di jQuery:

<span data-binding-name="Name" data-bind="MyBinding: Name"></span> 

ko.bindingHandlers.MyBinding = { 
    init: function (element, valueAccessor, allBindings, viewModel, context) { 
     var nameOfProp = $(element).data('binding-name'); 
    }, 
};