1

I've got a ko.observable in my viewmodel, which is attached to an input. When user changes value of that input (per-character) I run AJAX call, which downloads suggestions from backend.

When user chooses one of suggestions, I'd like to fill the input with chosen value, but without sending the AJAX call. But setting observable's value will still trigger event and call function attached to textInput binding.

How can I set observable's value without triggering textInput?

Sample code:

var name = ko.observable(); name.subscribe(nameChanged); var nameChanged = function() { someService.post(name(), success, failure); } var someAction = function() { name("Test"); // I don't want to trigger AJAX call here } 
<input type="text" data-bind="textInput: name" /> 

4 Answers 4

1

Another option is to use a computed observable as an intermediary. The ajax function can trigger in the write event of the computed so that direct writes to the observable bypass it.

function viewModel(){ var self = this; self.realName = ko.observable('test'); self.Name = ko.computed({ read: function(){ return self.realName(); }, write: function(value){ self.realName(value); nameChanged(value); } }); function nameChanged(newName) { console.log("name changed:", newName); } self.modifyName = function(){ self.realName(self.realName() + 'z'); } } ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <input type="text" data-bind="textInput: Name" /> <br /> <button data-bind="click: modifyName">Modify</button>

Sign up to request clarification or add additional context in comments.

1 Comment

I ended with two observables: name and displayName. I also subscribed to changes and when one is changed and another is different, the first one updates second one. But now I know, from where the change came: if displayName updates name - from user, and if name updates displayName, from code. Your solution is more elegant though.
0

Maybe set a particular CSS class on the field after the selection is made and put some logic around the ajax call to check if the field has the CSS class.

Comments

0

Instead of subscribing to the change event of the observable you could tie your ajax call to the change event of the ui element instead. You would get rid of name.subscribe(nameChanged); and add an event binding:

data-bind="textInput: name, event: { changed: nameChanged }" 

1 Comment

This is not that easy. I need to trigger that AJAX call after each value change, eg. after each keypress (including paste, mouse text drag etc.), because I'm requesting autocomplete suggestions for that input. Whereas changed is called only when input loses focus...
0

An "old fashioned" way that works, but is not really elegant, is to temporarily dispose the subscription and then reattach it:

var myName = ko.observable(); var nameSub = myName.subscribe(nameChanged); function nameChanged(newName) { console.log("name changed:", newName); } function changeWithoutLog() { nameSub.dispose(); myName("Test"); nameSub = myName.subscribe(nameChanged); } ko.applyBindings({ name: myName });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> <input type="text" data-bind="textInput: name" /> <button data-bind="click: changeWithoutLog">change without post</button>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.