2013-01-16 11 views
6

Powiedzmy mam związany rozpiętośćJak uzyskać ekspresję wiążącej wewnątrz BindingHandler w Knockout JS

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

I mam zwyczaj wiązania

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

jaki sposób uzyskać ciąg z wartość wyrażenia wiążącego wewnątrz programu obsługi? tj. jak uzyskać "Nazwa", a nie "Wartość nazwy".

również potrzebne wyrażenie tak przepuszczenie „Nazwa” ciąg nie jest wykonalne.

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

Odpowiedz

2

Rzeczywiście, nokaut ma ma wbudowany sposób, aby to zrobić. Musisz nieco dostosować swoje niestandardowe powiązanie (mianowicie staje się obiektem zamiast wartością ciągu znaków). Knockout pozwala, wraz z właściwościami init i update, określić właściwość preprocess. Na przykład, załóżmy, że mamy następującą ViewModel:

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

i prostego wiązania, które przekonwertować ciąg przekazany do niego całkowicie na małe litery oraz wyjście zarówno wiązania jego wartość nazwę i (własność przeszła w widoku oczywiście będąc 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 + '\'}'; 
    } 
}; 

jest to tak proste, jak stringifying właściwość value przekazany do niego & przekształcania wartości wiązania użytkownika do obiektu z 2 kluczami (nazwa & wartości tutaj). Have a look. Aby uzyskać więcej informacji, patrz Binding preprocessing.

2

Trzeba zdać w Name jako ciąg znaków, a nie jako odniesienie:

<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 
    }, 
}; 

można nadal używać swój wyraz w postaci ciągu znaków, ponieważ w JavaScript można eval altough eval() jest niebezpieczna funkcja: tutaj jest próbka JSFiddle.

Jeśli potrzebujesz tylko obsługi prostego wyrażenia właściwości, takiego jak Child.Name, możesz napisać własny analizator składni, w którym podzielisz ciąg na kropki i foreach na akcesoriach.

+0

Jak to działa, jeśli jest to złożone wyrażenie. np. "Child.Name" – Simon

+0

Dlaczego ciąg nie będzie dla ciebie działać? W JavaScript możesz 'eval' w zasadzie dowolny ciąg na kod JS. – nemesv

+0

Oczywiście. pozwól mi spróbować. – Simon

1

Można wykonać następujące czynności, więc nie trzeba będzie 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()); 
    } 
}; 

Jak już wyjaśniono, trzeba podać nazwę jako wartość ciągu w swojej wiążące. Następnie możesz użyć tego do przejścia przez swój model widoku w celu pobrania wartości. Aby wyświetlić wartość w elemencie Dodałem $(element).html(current()); Tutaj current() jest na najgłębszym poziomie w moim viewmodel tak to można nazwać, a wartość powrotu może być wykorzystane do aktualizacji html.

+0

Czy możesz opisać, co jest "następujące"? Dlaczego odpowiada na pytanie? Możesz [edytować] swoją odpowiedź, aby dołączyć opis. –

+0

Po prostu rozwinąłem odpowiedź @nemesv podaną. Poniżej mam na myśli następujący fragment kodu – gkempkens

0

Jestem trochę późno na imprezę na ten temat, ale tutaj jest to, co zrobiłem, i to działa jak czar:

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> 

Tak więc wartość akcesor (w przypadku pominięcia komentarza) będzie "myProp.childProp"

1

Proponuję przenieść nazwę pro z użyciem innego wiązania.

<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

Lubię to, co powiedział Pavel-chervov powyżej. W podobnym duchu, jeśli nie masz nic przeciwko używaniu odrobiny 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'); 
    }, 
}; 
Powiązane problemy