2016-05-15 2 views
3

Wie lautet die Syntax (vorausgesetzt, es gibt eine), input Steuerelement value an eine Viewmodel-Funktion zu übergeben? In meinem Szenario bin ich nicht daran interessiert, den Wert der Eingabe an eine Eigenschaft im Viewmodel zu binden. Ich muss nur auf den Wert reagieren, der in das Eingabesteuerelement eingegeben wurde (im Grunde wiederhole ich eine Auflistung von Elementen und filtere diejenigen heraus, die den eingegebenen Text nicht enthalten).Übergabe des Werts des Eingabeelements als Parameter an eine Viewmodel-Funktion

<input data-bind="text: filterText($data), valueUpdate: 'afterkeydown'"> 

habe ich versucht, filterText($data, value) aber Knockout versucht value Eigenschaft auf dem Viewmodel zu finden. Ich brauche tatsächlich den aktuellen Wert aus dem Eingabesteuerelement.

Ist das möglich?

Antwort

4

Der typische Umgang mit diesem Anwendungsfall besteht in der Verwendung einer textInput Bindung mit einem Abonnement für den gebundenen Wert, der filterText aufruft.

<input data-bind="textInput: filter"> 

In Ihrem Skript:

filter.subscribe(function(newValue) { 
    filterText(newValue) 
}); 

, die Sie vereinfachen könnten:

filter.subscribe(filterText); 

Aber Sie sind wahrscheinlich immer noch über diese falsch zu denken. Ihre gefilterte Liste sollte eine berechnete sein, die auf den textInput-gebundenen Wert filter verweist, um die gefilterte Liste zu berechnen.

filteredList = ko.pureComputed(function() { 
    // return the list filtered by the bound filter() value 
}, self); 

Dann können Sie filteredList() verwenden, wo immer Sie die gefilterte Liste der Daten benötigen.

0

Wenn Sie die Eigenschaft nicht an das Ansichtsmodell binden, können Sie jquery/javascript verwenden, um den Wert dieses Eingabesteuerelements direkt in Ihrer Ansichtsmodellfunktion abzurufen.

self.Filter= function() {   
    var filter = $('#textBoxID').val(); 
    //  
} 

Auf diese Weise müssen Sie den Wert nicht an den View-Model-Funktionsparameter übergeben.

+0

warum down-vote ohne grund? – pso

+0

Dies funktioniert nicht mit dem Ansichtscode von OP, der eine 'text' Bindung hat. Auch unter der Annahme einer "value" -Bindung wird diese Lösung technisch funktionieren, aber es ist überhaupt kein idiomatischer KnockoutJS, der sich auf einen Nebeneffekt davon verlässt, wie KO intern arbeitet und nach meiner Erfahrung Probleme auf der Straße verursacht. – Jeroen

+0

Aber der Typ hat gesagt "In meinem Szenario bin ich nicht daran interessiert, den Wert der Eingabe an eine Eigenschaft im Viewmodel zu binden." Meine Lösung funktioniert für sein Szenario, glaube ich. – pso

1

Erste Dinge zuerst. Ihr Beispiel-Code verwendet a text binding auf einem input-Knoten, der nicht so nützlich ist (es würde eine One-Way Bindung von Ansicht Modell zu DOM, der "Text" Inhalt dieser input, die nicht sinnvoll ist). Angesichts der valueUpdate Bindung Sie wahrscheinlich the value binding? Beachten Sie übrigens, dass der Weg ist, diese beiden in modernen Versionen von KnockoutJS zu kombinieren.

Was Ihre eigentliche Frage betrifft, fehlen wichtige Kontext: Warum Sie (denken Sie) wollen, dies zu tun? Je nach Kontext ist die Lösung anders, oder Sie haben sogar eine XY-problem.

In jedem Fall zu den Antworten.

Option 1
Der Versuch, dennoch die konkrete Frage zu beantworten, ich zweite @JohnnyHK's answer eines .subscribe auf beobachtbaren als eine mögliche Lösung zu schreiben.

Option 2
Eine andere mögliche Lösung stark ähnelt, dass ein, sondern versuchen, gerecht zu werden „Ich bin nicht daran interessiert, den Wert des Eingangs“ -Teil, schlage ich mit einem Nur-Lese-beobachtbaren berechnet:

function Root() { 
 
    var self = this; 
 
    
 
    self.filter = ko.computed({ 
 
    read: function() { return ""; }, // <-- not recommended, read context! 
 
    write: function(newValue) { 
 
     // You're free to discard the newValue <-- not recommended, read context! 
 
     alert("Input has been changed."); 
 
    } 
 
    }); 
 
} 
 

 
ko.applyBindings(new Root());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script> 
 
<input data-bind="textInput: filter">

Nun ist diese verwirft ausdrücklich die newValue im Schreib-Bit (wie pro Ihre Anfrage), und damit auch ha s eine seltsam aussehende read Funktion. Ich empfehle das nicht, und stattdessen würde empfehlen, eine private Variable mit einer beobachtbaren Unterstützung zum Lesen und Schreiben zu verwenden. Effektiv würde dies jedoch diese Option der ersten Option aus der anderen Antwort gleichwertig machen. obwohl

Eine interessante Anmerkung, etwas Ihre Frage ist über „die collectin“ und Filtereingang: wenn man sich the docs from writeable computeds aussehen werden Sie feststellen, dass die Benutzer Eingabe zu akzeptieren oder nicht, ob es eine bestimmte Bedingung erfüllt ist in der Tat ein Anwendungsfall dafür.

Option 3
Was ich aber empfehlen würde, wenn ich Ihre Anfrage ein wenig anders formulieren:

Wie gehen Sie mit idiomatischen KnockoutJS zu inputvalue Änderungen reagieren, wenn Ihre Aktion nicht kümmern sich um die tatsächliche value?

Zum Schreiben einer benutzerdefinierten Interaktion mit dem DOM gibt es custom binding handlers. Sie können entweder eine verwenden, die das ViewModel überhaupt nicht verwendet, oder eine, die eine Observable hat.

Option 3.A

ko.bindingHandlers["opacitor"] = { 
 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
 
    $(element).on("keydown", function() { 
 
     $(this).animate({ opacity: 0.05 }, 1000, function() { $(this).animate({ opacity: 1.0 }, 1000); }); 
 
    }); 
 
    } 
 
} 
 

 
ko.applyBindings({});
input { background-color: gold; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script> 
 

 
<input data-bind="opacitor">

Option 3.B
Oder eine zweite Option, die das View-Modell nicht verwendet:

ko.bindingHandlers["opacitor"] = { 
 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
 
    $(element).on("keydown", function() { 
 
     var speed = ko.utils.unwrapObservable(valueAccessor)(); 
 
     $(this).animate({ opacity: 0.05 }, speed, function() { $(this).animate({ opacity: 1.0 }, speed); }); 
 
    }); 
 
    } 
 
} 
 

 
// speed1 and speed2 could also be observables 
 
ko.applyBindings({ speed1: 500, speed2: 2000 });
input { background-color: gold; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script> 
 

 
<input data-bind="opacitor: speed1"> 
 
<input data-bind="opacitor: speed2">

Der Nachteil beider Optionen 3A und 3B ist, dass Sie benutzerdefinierte Ereignisbehandlungslogik schreiben müssen. Wenn Sie einen Blick auf the textInput source from KO werfen, werden Sie sehen, dass es nicht trivial ist, um diese Dinge korrekt Cross-Browser zu behandeln. Die Verwendung von Option 1 oder 2 könnte also immer noch besser sein (auch wenn Sie eine Interaktion mit dem Ansichtsmodell haben, obwohl "Sie nicht interessiert sind").

Option 4
Verwendung the event binding. Dies hat die gleichen Nachteile wie Option 3, könnte aber trotzdem eine einfache Lösung sein.Hier ein Beispiel:

function Root(){ 
 
    var self = this; 
 
    self.myFn = function(data, element) { 
 
    console.log(element.target.value); 
 
    return true; 
 
    }; 
 
} 
 

 
ko.applyBindings(new Root());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script> 
 
<input data-bind="event: { keyup: myFn }">

Eine subtile Änderung, die Sie in diesem letzten sehen werden, und eine Frage, die ich beenden möchten mit: hast in dir tatsächlich nicht this issue haben, wo Sie wirklich brauchen der neue Wert und sollte daher nicht auf afterkeydown betrachten, aber für ein anderes Ereignis?

1

Verwenden Sie $ element.value, um auf den Wert der Eingabe zuzugreifen.