I have element in html, which have data-bind for css.
The field behind is ko.computed.
In the computed function, I need to access to the id of the element.
How can I get the element at the ko.computed function?
Code example:
<span id="ship" style="cursor:pointer" data-bind="click:changeItem, css:computeActive" >ship</span>
<span id="cat" style="cursor:pointer" data-bind="click:changeItam, css:computeActive" >cat</span>
<span id="dog" style="cursor:pointer" data-bind="click:changeItem, css:computeActive" >dog</span>
view model:
var vm = {
computeActive: function () {
return data.selectedItem()== (****here is the place where I want to use object id****)?
"activeText":"inActiveText" ;
},
changeItem: function (event, sender) {
data.selectedItem(sender.currentTarget.id);
}
};
I don't want:
1. to use knockout.bindingHandler
2. to write separated computed-function for each element
In the computed function, I need to access to the id of the element.
No, you don't.
Your view model never needs to know anything about your view. (In other words, if it does, you're doing something wrong.)
Better view model (thanks to #xdumaine assisting):
function VM() {
var self = this;
self.items = ko.observableArray(['ship', 'cat', 'dog']);
self.selectedItem = ko.observable();
self.computeActive = function (item) {
return self.selectedItem() === item ? "activeText" : "inActiveText";
};
self.selectItem = function (item) {
self.selectedItem(item);
}
};
ko.applyBindings(new VM());
and the view
<div data-bind="foreach: items">
<span data-bind="click: $root.selectItem, css: $root.computeActive($data), text: $data"></span>
</div>
See it in action: http://jsfiddle.net/6998N/5/
Passing $data (i.e. the item itself) like this css: $root.computeActive($data) is necessary in this case because it forces KnockOut to re-evaluate the css binding for every item individually, every time.
See http://jsfiddle.net/6998N/4/ for an alternative approach.
if you don't want to make custom binding handler then you can manually pass the id.
var vm = {
computeActive: function (id) {
return data.selectedItem()== id?"activeText":"inActiveText" ;
},
changeItem: function (event, sender) {
}
};
html:-
<span id="ship" style="cursor:pointer" data-bind="click:changeItem, css:computeActive('ship')" >ship</span>
<span id="cat" style="cursor:pointer" data-bind="click:changeItem, css:computeActive('cat')" >cat</span>
<span id="dog" style="cursor:pointer" data-bind="click:changeItem, css:computeActive(dog')" >dog</span>
Sample Fiddle
Related
I have a list as follows:
<ul id="blogList" data-bind="foreach: Data">
<li>
<span data-bind="text: Title"> </span>
View
</li>
</ul>
And knockout view model as below:
var ViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
this.currentSelected = ko.observable();
self.viewEntry = function () {
currentSelected = this;
}
};
Setting the currentSelected to this doesn't seem to work because when I try to bind to currentSelected somewhere else I get nothing happening:
<h2 data-bind="text: currentSelected.Title"></h2>
Is that the correct way to bind to currentSelected? The list is working fine but setting the currentSelected and binding to it isn't working.
First let's have a look at your viewEntry method.
self.viewEntry = function () {
currentSelected = this;
}
currentSelected is undefined it should be self.currentSelected additionally since this is an observable you should not set this as var with equal sign but rather treat this as function so it should be self.currentSelected(this)
the other thing is binding inside this part:
<h2 data-bind="text: currentSelected.Title"></h2>
again this is an object so to access its properties you need to use currentSelected as function so it should be
<h2 data-bind="text: currentSelected().Title"></h2>
Here you can find a working sample: https://jsfiddle.net/jz9t5vbo/
Here is the fiddle demonstrating the problem http://jsfiddle.net/LkqTU/31955/
I made a representation of my actual problem in the fiddle. I am loading an object via web api 2 and ajax and inserting it into my knockout model. however when I do this it appears the attributes are no longer observable. I'm not sure how to make them observable. in the example you will see that the text box and span load with the original value however updating the textbox does not update the value.
here is the javascript.
function model() {
var self = this;
this.emp = ko.observable('');
this.loademp = function() {
self.emp({
name: 'Bryan'
});
}
}
var mymodel = new model();
$(document).ready(function() {
ko.applyBindings(mymodel);
});
here is the html
<button data-bind="click: loademp">
load emp
</button>
<div data-bind="with: emp">
<input data-bind="value: name" />
<span data-bind="text: name"></span>
</div>
You need to make name property observable:
this.loademp = function(){
self.emp({name: ko.observable('Bryan')});
}
I have searched and I have tried different selectors but I can't figure this out. I am following a tutorial, but I am not getting a result.
The click event doesn't seem to be binding to the dynamically generated div section '.person-brief'? There is no click event associated with it. I tried .live() also, but that seems to have been deprecated.
Any idea what I am doing wrong?
person.js model
var gotoDetails = function (selectedPerson) {
if (selectedPerson && selectedPerson.id()) {
var url = '#/persondetail/' + selectedPerson.id();
router.navigateTo(url);
}
};
var viewAttached = function (view) {
bindEventToList(view, '.person-brief', gotoDetails);
};
var bindEventToList = function (rootSelector, selector, callback, eventName) {
var eName = eventName || 'click';
$(rootSelector).on(eName, selector, function () {
var ser = ko.dataFor(this);
callback(ser);
return false;
});
};
var vm = {
people: people,
title: 'people demo',
viewAttached: viewAttached
};
return vm;
person.html view
<section id="person-view" class="view">
<header>
<a class="btn btn-info btn-force-refresh pull-right"
data-bind="click: refresh" href="#"><i class="icon-refresh"></i>Refresh</a>
<h3 class="page-title" data-bind="text: title"></h3>
<div class="article-counter">
<address data-bind="text: people().length"></address>
<address>found what</address>
</div>
</header>
<section class="view-list" data-bind="foreach: people">
<article class="article-left-content">
<div class="person-brief" title="Go to person details">
<small data-bind="text: firstname" class="right"></small>
<small data-bind="text: lastname"></small>
</div>
</article>
</section>
</section>
With KnockoutJS you should use the click binding (or alternatively the event binding), not use jQuery to manually manipulate the DOM.
Something like this becomes your code:
var vm = {
people: people,
title: 'people demo',
viewAttached: viewAttached
};
vm.myHandler = function (person) {
goToDetails(person);
return false;
};
And since myHandler is so simple you might as well inline the goToDetails code, which has access to vm from its closure.
You bind in the view like this:
<div class="person-brief" data-bind="click: $root.myHandler">
...
</div>
A general tip: do a tutorial on either jQuery, or KnockoutJS. If you take the latter, try to use as little is possible jQuery (which is usually quite possible), most notably don't use jQuery to manipulate the DOM (except in custom binding handlers and after-render functions).
I'm having trouble binding my click action to the view model function to remove an item from an array (inside a foreach binding)
I've got the following view model
var FileGroupViewModel = function () {
var self = this;
self.files = ko.observableArray();
self.removeFile = function (item) {
self.files.remove(item);
}
self.fileUpload = function (data, e) {
var file = e.target.files[0];
self.files.push(file);
};
}
var ViewModel = function () {
var self = this;
self.FileGroup = ko.observableArray();
self.FileGroup1 = new FileGroupViewModel();
self.FileGroup2 = new FileGroupViewModel();
self.FileGroup3 = new FileGroupViewModel();
self.uploadFiles = function () {
alert("Uploading");
}
}
var viewModel = new ViewModel();
ko.applyBindings(viewModel);
And my view, which basically lists 3 "groups" of buttons, where a user can select files to upload
Everything below is working as expected, except $parent.removeFile isn't removing the file:
<div class="row files">
<h2>Files 1</h2>
<span class="btn btn-default btn-file">
Browse <input data-bind="event: {change: FileGroup1.fileUpload}" type="file" />
</span>
<br />
<div class="fileList" data-bind="foreach: FileGroup1.files">
<span data-bind="text: name"></span>
Remove
<br />
</div>
</div>
Fiddle at https://jsfiddle.net/alexjamesbrown/aw0798p7/
Am I wrong to do $parent.removeFile - it seems this doesn't get called on click?
This is a cut down working example, not the finished product!
You're misunderstanding $parent. It takes you out one context level. Your foreach uses FileGroup1.files as its index, so you might think that the $parent level would be Filegroup1, but it's not. It's the top-level viewmodel, because that is the context outside the foreach.
So your click binding should be
click: $parent.FileGroup1.removeFile
Note: This is not a question about ObservableArrays.
Let's say I have the following viewmodel:
var viewmodel = {
arrayOfBooleans: [
ko.observable(false),
ko.observable(false),
ko.observable(false)
]
}
And a view like so:
<div data-bind="foreach: arrayOfBooleans">
<button data-bind="click: ????">Set to true</button>
</div>
What can I do inside the foreach to get the <button> to set the observable to true when clicked? Using data-bind="click: someFunction", the first argument someFunction gets is the unwrapped values of observables in the array (not the observables themselves), and seemingly no way to get back at the observables or to pass custom arguments.
Hope it will give some idea .
var viewmodel = {
var self = this;
self.arrayOfBooleans = ko.observableArray([]);
self.arrayOfBooleans.push(new _newBoolean());
self.arrayOfBooleans.push(new _newBoolean());
self.arrayOfBooleans.push(new _newBoolean());
function _newBoolean() {
self.one = ko.observable(false);
}
self.setToTrue = function(index){
self.arrayOfBooleans()[index].one(true);
};
}
If you want it as button
<div data-bind="foreach: arrayOfBooleans">
<button data-bind="click: $root.setToTrue($parent.arrayOfBooleans.indexOf($data))">
Set to true
</button>
<input type=hidden data-bind="value:one" />
</div>
If you want it as radio button than it is much more simple
<div data-bind="foreach: arrayOfBooleans">
<span>Set To True</span><input type=radio data-bind="value:one" />
</div>
If you like this..Please Click uplink
*or*
If it solves your problem .. Mark this as answer