I have been following some tutorials and trying to follow knockout.js. I am not able to edit any data that is newly added.
My JS Code:
var data = [
new ListData("Programmer", 1),
new ListData("Testing", 2),
new ListData("DBA", 3),
new ListData("Lead", 4),
new ListData("Manager", 5)
];
function ListData(desig, id) {
return {
Desig: ko.observable(desig),
Id: ko.observable(id)
};
}
var viewModel = {
list: ko.observableArray(data),
dataToAdd: ko.observable(""),
selectedData: ko.observable(null),
addTag: function () {
this.list.push({ Desig: this.dataToAdd() });
this.tagToAdd("");
},
selecData: function () {
viewModel.selectedData(this);
}
};
$(document).on("click", ".editData", function () {
});
ko.applyBindings(viewModel);
My View Code:
<input type="text" data-bind="value: dataToAdd" />
<button data-bind="click: addData">
+ Add
</button>
<ul data-bind="foreach: list">
<li data-bind="click: $parent.selecData">
<span data-bind="text: Desig"></span>
<div>
Edit
</div>
</li>
</ul>
<div id="EditData" data-bind="with: selectedData">
Designation:
<input type="text" data-bind="value: Desig" />
</div>
I am able to edit the data which already exists like - Programmer, Testing, DBA...but if I add a new data..I am not able to edit. Please assist.
Your addData (you named it addTag in the code, but call addData in the HTML) function doesn't construct new elements the same way your initial data creation does. Note: since your ListData constructor explicitly returns an object, new is superfluous.
addData: function () {
this.list.push(ListData(this.dataToAdd(), ""));
},
Related
I have a knockout observable array whose value assignment changes after a set value of time but do not see this reflecting in the view. Could someone tell where I am doing it wrong? I would expect the output to show
• GRE 1111
• TOEFL 111
but it shows
• GRE2 222
• TOEFL2 22
jsFiddle link: https://jsfiddle.net/4r37x9y5/
HTML:
console.clear();
function viewModel() {
this.plans = ko.observableArray([]);
var plans1 = [
{ id: 'GRE', count: '1111' },
{ id: 'TOEFL', count: '111' },
];
var plans2 = [
{ id: 'GRE2', count: '222' },
{ id: 'TOEFL2', count: '22' },
];
this.plans = plans2;
//this.plans = plans1;
setTimeout(function(){
console.log("In timeout before assigning plans");
this.plans = plans1;
console.log(this.plans);
}, 2000);
}
ko.applyBindings(viewModel());
// The above line equals:
// viewModel(); // updates window object and returns null!
// ko.applyBindings(); // binds window object to body!
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="panel panel-default">
<ul data-bind="foreach: plans" class="list-group">
<li class="list-group-item">
<span data-bind="text: id"></span>
<span data-bind="text: count"></span>
</li>
</ul>
</div>
There are couple of issues here. As mentioned by you in the comments, you are not binding an object with observables. You are simply adding a global variable plans. If knockout can't find a property in the viewModel, it will use the window object's property. That's why it works the first time
You need to change viewModel as a constructor function and use new viewModel() to create an object or an instance.
observables should be read and updated by calling them as functions. So, this.plans(plans1). If you set this.plans = plans2, it will simply overwrite the observable with a simple array without the subscribers to update the UI when the property changes
You need to use correct this inside setTimeout. Either by creating a self = this variable outside or using an arrow function as a callback
function viewModel() {
this.plans = ko.observableArray([]);
var plans1 = [{ id: "GRE", count: "1" }, { id: "TOEFL", count: "1" }];
var plans2 = [{ id: "GRE2", count: "2" }, { id: "TOEFL2", count: "2" }];
this.plans(plans2) // call it like a function
setTimeout(() => {
console.log("In timeout before assigning plans");
this.plans(plans1)
}, 2000);
}
ko.applyBindings(new viewModel()); // new keyword to create an object
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: plans">
<li>
<span data-bind="text: id"></span>
<span data-bind="text: count"></span>
</li>
</ul>
I need some help here: https://jsfiddle.net/vhaurnpw/
I want to do a simple list, which is filterable by the input on top and updates itself..
JS/Knockout:
var viewModel = {
query: ko.observable(''),
places: ko.observable(data),
search: function(value) {
viewModel.places = [];
console.log(value)
for (var i = 0; i < data.length; i++) {
if(data[i].name.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
viewModel.places.push(data[i]);
}
console.log(viewModel.places);
}
}
};
viewModel.query.subscribe(viewModel.search);
ko.applyBindings(viewModel);
HTML:
<form acion="#" data-bind="submit: search">
<input placeholder="Search" type="search" name="q" data-bind="value: query, valueUpdate: 'keyup'" autocomplete="off">
</form>
<ul data-bind="foreach: places">
<li>
<span data-bind="text: name"></span>
</li>
</ul>
List will be rendered, but it when you type something, it doesn't show you the result.
Instead when you lookup the console, you will see the console.log and it updates just fine!
so how do i refresh my HTML? :(
There are following issues in your code.
places needs to be an ObservableArray and not an Observable so that you can track the addition/removal from the Observable Array. So, change code From places: ko.observable(data) To places: ko.observableArray(data),
viewModel.places is function, so when you assign another value like viewModel.places = [], it is assigning an empty array to the viewModel.places. In order to modify the value of the viewModel.places, you need to call it as a function like viewModel.places([]);
Note: Your code doesn't add the data back in case the textbox is cleared, I hope you got the solution to the problem and you can resolve this issue as well.
Complete Working Code:
var data = [
{ name: 'Isartor'},
{ name: 'Sendlinger Tor'},
{ name: 'Marienplatz'},
{ name: 'Stachus'},
{ name: 'Bayerischer Rundfunk'},
{ name: 'Google München'},
{ name: 'Viktualienmarkt'},
{ name: 'Museumsinsel'},
{ name: 'Tierpark Hellabrunn'},
{ name: 'Allianz Arena'},
{ name: 'Olympia-Park'},
{ name: 'Flaucher-Insel'}
];
var viewModel = {
query: ko.observable(''),
places: ko.observableArray(data),
search: function(value) {
viewModel.places([]);
console.log(value)
for (var i = 0; i < data.length; i++) {
if(data[i].name.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
viewModel.places.push(data[i]);
}
console.log(viewModel.places);
}
}
};
viewModel.query.subscribe(viewModel.search);
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<form acion="#" data-bind="submit: search">
<input placeholder="Search" type="search" name="q" data-bind="value: query, valueUpdate: 'keyup'" autocomplete="off">
</form>
<ul data-bind="foreach: places">
<li>
<span data-bind="text: name">asd</span>
</li>
</ul>
I'm a new programmer for knockout.
Here's a question about ko.observableArray while practicing.
I give an zero-based index array for initial data that will show with JSON while clicking button.
But when I try to update any value from input field but I cannot get the new JSON after clicking button.
And I think the problem is that there's no index in my array.How can I get the new JSON after clicking
function ViewModel(inputs){
this.inputs = ko.observableArray(inputs);
this.getData = function(){
this.jsonData(ko.toJSON(this.inputs));
};
this.jsonData = ko.observable('');
};
var initialData = [ 'Jan', 'Feb', 'Mar', 'etc' ];
var viewModel = new ViewModel(initialData);
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<ul data-bind="foreach: inputs">
<li>
The current item is: <input type='text' data-bind="value: $data"></b>
</li>
</ul>
<textarea rows='5' cols='60' data-bind='value: jsonData'> </textarea>
<button data-bind='click: getData'>get Data</button>
I thing due to $index you can't get this updated JSON
if you add key value pair in "initialData" you will get updated JSON data
Here blow working code :
function ViewModel(inputs) {
this.inputs = ko.observableArray(inputs);
this.getData = function () {
this.jsonData(ko.toJSON(this.inputs));
};
this.jsonData = ko.observable('');
};
var initialData = [{ name: 'Jan' }, { name: 'Feb' }, { name: 'Mar' }, { name: 'etc' }];
var viewModel = new ViewModel(initialData);
ko.applyBindings(viewModel);
<ul data-bind="foreach: inputs">
<li>
The current item is: <input type='text' data-bind="value: name"><br />
</li>
</ul>
<textarea rows='5' cols='60' data-bind='value: jsonData'> </textarea>
<button data-bind='click: getData'>get Data</button>
I'm trying to reassign an object value in foreach with click on removePollOption function
<div data-bind="foreach: pollOptions">
<input data-bind="value: title">
<div data-bind="text: destroy">
<a href='#' data-bind='click: $root.removePollOption'></a>
</div>
pollOptions array:
this.pollOptions = ko.observableArray(ko.utils.arrayMap(optionsInitialData, function(pollOption) {
return { id: pollOption.id, title: pollOption.title, destroy: pollOption.destroy };
}));
but when I try to do it in function value is not changing dynamically
this.removePollOption = function() {
this.destroy = true;
};
If i try this.destroy(true); I get an error Uncaught TypeError: boolean is not a function
I understood that I should declare destroy as observable like
this.pollOptions = ko.observableArray(ko.utils.arrayMap(optionsInitialData, function(pollOption) {
return { id: pollOption.id, title: pollOption.title, destroy: ko.observable(false) };
}));
I have a html 5 view and want to perform Drag and Drop. In my html I have a knockout foreach as given below. The li element is being dragged on.
<ul class="games-list" data-bind="foreach: games">
<li data-bind="text: name, attr: { 'data-dragdrop': id }"
ondragstart='setTransferProperties(event)'
draggable="true">
</li>
</ul>
and here is the javascript with knockout ViewModel
<script type="text/javascript">
var AppScope = function () {
...//plain js object here
//knockout js View Model
function PlayersViewModel() {
var self = this
self.games = ko.observableArray([
new Game({ id: 0, name: "Cricket" }),
new Game({ id: 1, name: "Football" }),
new Game({ id: 2, name: "Hockey" })
]);
...
//Drag and Drop
self.setTransferProperties = function (event) { //Not invoked
event.dataTransfer.setData("Text", event.target.getAttribute('data-dragdrop'));
};
}
}
With the above the setTransferProperties(event) is looked for in AppScope, instead of inside the knockout ViewModel, and hence not found.
What would be the way to invoke the setTransferProperties(event) defined in the knockout ViewModel when performing the Drag.
You need to do the following
<ul class="games-list" data-bind="foreach: games">
<li data-bind="text: name, attr: {
'data-dragdrop': id ,
'ondragstart':$parent.setTransferProperties
}"
draggable="true">
</li>
</ul>