I cannot understand why this small code is not working properly.Please help!
All i try is to push textbox values into an array and then then display it back using a binding.
HTML code is :
<div>
Add Task:<input type="text" placeholder="abcd" data-bind="value:viewModel.newTask"/>
<input type="button" value="add" data-bind="click:viewModel.addTask" />
</div>
<div data-bind="foreach:viewModel.tasks" ></div>
js script is:
var viewModel = function (items) {
var self = this;
self.newTask = ko.observable();
self.tasks = ko.observableArray(items);
self.addTask = function () {
self.tasks().push(self.newTask());
self.newTask(" ");
}
ko.applyBindings(viewModel(["alpha","beta","gamma"]));
}
i tried it in JSFiddle also:
http://jsfiddle.net/Rakz_1221/m3rwupmz/1/
First off, you haven't included KnockoutJS in your JSFiddle demo, so your demo will not work anyway.
The problem you have is that you're calling tasks.push. tasks itself isn't an array. tasks is a function - a Knockout Observable. In order to push values into it, we need to execute this function by calling tasks().push() instead.
As James Thrope has commented, you can in fact call tasks.push, sorry about that!
Finally, your ko.applyBindings(...) is never being called as it's contained within your viewModel function - which you're not calling at any point.
I strongly advise you to go through KnockoutJS's very own interactive tutorial available at http://learn.knockoutjs.com.
Related
I've read lots of stackoverflow questions with no luck. My problem is, I have an HTML page in which I have
<select id="myid"></select>
and there, there's a Firebase command that retrieves names of values i need, and put it inside the <option> like HERE:
reference.on("child_added", function (childSnapshot){
var key = childSnapshot.key;
var opt = document.createElement('option');
opt.textContent = key;
document.getElementById('myid').appendChild(opt);
});
Now, i need to somehow access these values, that by the way are correctly appearing in both HTML and my site, however:
var val = document.getElementById('myid').value;
console.log(val);
It always returns blank in console. I don't know how else can I access it. Whenever I type those values in <option> by myself in HTML, everything works as it should and console returns the names that are in database.
#edit: as far as i tried to crack it, it seems to do with the fact that javascript cannot access elements, that for javascript itself aren't yet loaded, but i tried doing window.onload and other similar ones and they don't help.
You can use AngularJS, with directive $scope.watch, i will write a simple example of how to use and the link of documentation, if you have any question talk back to me!
function MyController($scope) {
$scope.myVar = 1;
$scope.$watch('myVar', function() {
alert('hey, myVar has changed!');
});
$scope.buttonClicked = function() {
$scope.myVar = 2; // This will trigger $watch expression to kick in
};
}
AngularJS Documentation
I hope help with this :)
I have a VM with the following:
var myArray = ko.observableArray(),
....
addItem = function(data) {
myArray.unshift(data);
},
In my View I have some HTML that binds to it:
<div data-bind="foreach: myArray">
....<label data-bind:="attr: { id: 'myLabel_' + name }"></Label>
</div>
Everything works great - when I call the addItem function an item gets added to my obserableArray() and Knockout adds the appropriate HTML.
The problem I'm facing now is when, instead of just using plain HTML, I try to use a more complex control (like a Kendo grid). I need to call a Javascript method to initiate the Grid when I call newItem. But if I do that, it doesn't work (I assume because Knockout hasn't 'finished' doing what it does, when the Kendo control tries to do what it needs to do).
The following doesn't work:
var myArray = ko.observableArray(),
....
addItem = function(data) {
myArray.unshift(data);
var test = $('#myLabel_nameOne');
// Kendo specific code to setup test
},
If I run the same Kendo specific code from the console - it works great. If I use a setInterval, that will work too.
I know there is an 'afterRender' I can hook into on an entire template - but I'm just looking to know when the UI is done after adding a single item into that observableArray.
What's the proper way to say 'Wait until this is really added, then go do this other stuff?' Or 'Add this, and when the UI is ready, call this function for me'?
I've hit asynchronous issues with frameworks other than Knockout and usually solved them by writing wrappers with jQuery and the Deferred() object.
After reading Knockout documentation you can just use the subscribe function.
var myArray = ko.observableArray()
myArray.subscribe(function(data) {
var test = $('#myLabel' + data.name);
// Kendo specific code to setup test
});
....
addItem = function(data) {
myArray.unshift(data);
},
I'm creating a bug-handling program in KnockoutJS, and I've run into an issue. I have a list of "bug" reports on my main page that is displayed using an observable array. When I click "View" on one of the bug reports in the list, I have a Bootstrap modal pop up. I want to populate the contents of the modal with report details, but for some reason the viewmodel is not getting passed in correctly.
Here is my view model, along with my ajax mapping below that:
function BugsViewModel(doJSON) { //doJSON determines whether to populate the observable with JSON or leave it empty
var self = this;
self.bugs = ko.observableArray();
self.removeBug = function (bug) {
$.ajax({
url: "/ajax/getbugs.ashx?deleteBug=" + bug.Id()
})
self.bugs.remove(bug);
}
self.currentBug = ko.observable(); // <--this is the bug that I want to reference in the modal
self.setModalBug = function (obj, event) { //obj is the individual array item
self.currentBug = obj; //setting currentBug so that I can use it in my view
alert(self.currentBug.Id()); //<--these alert properly, so I know that the value I'm passing in (obj) is correct
alert(self.currentBug.BugName());
}
if(doJSON)
getViewModelJSON(self.bugs); //this function loads my array (self.bugs) with observable items
}
function getViewModelJSON(model) {
$.ajax({
url: "/ajax/getbugs.ashx"
})
.done(function (data) {
ko.mapping.fromJSON(data, {}, model);
});
}
$(document).ready(function () {
viewModel = new BugsViewModel(true);
ko.applyBindings(viewModel);
});
I have my "View" button, which calls "setModalBug" and opens the modal:
View
Then, inside my details modal, I have the textbox I want to populate with data. This is where I'm having the problem--currentBug.BugName is not populating the value correctly.
<input type="text" id="txtBugName" data-bind="textInput: currentBug.BugName" />
(Note that I am using the Mapping plugin for Knockout, so even though you don't see "BugName" defined in my viewmodal, it is being generated from the JSON when I call "ko.mapping.fromJSON()".)
I'm a little befuddled. Is this a runtime issue, or am I calling the viewmodel improperly? Or something entirely different?
Thanks
You're not assigning your value to the observable correctly. You're doing:
self.currentBug = ko.observable();
self.currentBug = obj;
The first line creates an observable, but the second line throws it away and replacing it with the bug object. You want to assign to the observable, not throw it away, like:
self.currentBug = ko.observable();
self.setModalBug = function (obj, event) {
self.currentBug(obj); //<-- Assign the current bug the currentBug observable
alert(self.currentBug().Id()); //note the additional () to read the value of the observable
alert(self.currentBug().BugName());
}
I got it working. Apparently in my code I actually didn't add the extra '()' to my alerts. Sorry--not my best moment. Now it works:
self.currentBug(obj);
alert(self.currentBug().Id());
alert(self.currentBug().BugName());
Then I added an extra '()' to my textInput data-bind:
<input type="text" id="txtBugName" data-bind="textInput: currentBug().BugName" />
I didn't realize that I had to use '()' anywhere on data-binds. I thought it figured out that you were working with observables and treated it that way (which it does on the property "BugName", but I had to access currentBug with '()' at the end).
Thanks, Retsam! I spent quite a lot of time on this and it was getting frustrating. Turns out it was a really simple fix.
Given any knockout example, I want to be able to identify the source of an observable update.
Consider for example this simple code:
HTML
<input type='text' data-bind='value: someValue' />
<span data-bind='text: someValue'></span>
<button data-bind='click: updateValue'>Update</button>
js
var vm = function () {
var self = this;
this.someValue = ko.observable('random value');
this.updateValue = function () {
self.someValue('random value ' + Math.round(Math.random()*10));
}
}
var vmi = new vm();
vmi.someValue('other random value');
ko.applyBindings(vmi);
Fiddle
I want to know if someValuewas last updated via the input tag, the button, or via code.
What do you think would be the best way to do so? (extender, custom binding handler, ...)
Create separate "writable computed observables" for each of those things to modify. See http://knockoutjs.com/documentation/computedObservables.html#writeable_computed_observables. In your write methods for each of these, you can handle differentiation/coordination/syncing between them as appropriate. There might be a better solution though if you described your actual scenario.
I'm working on a project that uses the mvc 4 api combined with vanilla mvc 4 for routing and views. Because we're using the web api\json all the data calls are client driven so we're creating a lot of javascript code.
To help with this we decided to create one global prototype javascript object for handling the stuff that is shared and include one javascript file per view to handle all client side code for that specific view. ( I know this isn't optimal )
My problem is with the per view javascript files. Should we create a prototype object per view, or use closures?
Without an object per view we see a trend, we usually end up with a $(document).ready, event wire ups like $(document).on('click', ..., view models, and a bunch of old school functions. It seems like there should be a way to organize these areas into something better. I've seen some suggestions on SO on how to do so but they don't show how to incorporate that jQuery load, event wire ups, and view models. Does anyone have any suggestions, or possible a simple example?
Here are the areas we normally end up with
$(document).ready(function () {....
$(document).on('click', '.button', function(e) {.....
function FooBar(){.....
I don't think there are any hard and fast rules for how to best accomplish this - lots of ways to skin this cat.
But here's what I do: I tend to create one (or more if necessary) closure objects for the page. It'll have an initialize method contains the $().ready() handler which then does all the event handler hookups, and any other page global initialization that needs to happen.
Something like this:
(function() {
function Page() {
var me = this;
// plain properties
this.prop = "value";
// compiled templates
this.template = HandleBars.compile($("#template1").html());
this.intialize = function () {
$().ready(function () {
$("#button1").click( me.button1Click );
$("#field1").change( me.field1Change );
});
};
this.button1Click = function () {
alert("click");
me.doSomething();
};
this.field1Change = function () {
alert("change");
},
this.doSomething = function (parm) {
alert("doSomething");
}
}
var page = new Page();
page.intialize();
})();
You should use one view model per view, and bind it to your view (html) with KnockoutJs, or any other resembling javascript library, which gives something like that (taken from there first example) :
view (html) :
<html>
<body>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
</body>
</html>
view model (javascript) :
var ViewModel = function(first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
};
get data from server, and populate view model (and view, consequently)
$.get('/info/path/', function(data) {
ko.applyBindings(new ViewModel(data.Planet, data.Earth));
});
Of course, if you're last part isn't at the end of the page, you can put it in a document.ready, or any similar method.