I'm relatively new to knockout and I've been researching my topic for hours to no avail, so I finally find myself actually asking a question on SO that I don't think has been asked.
Anyway, I'm coding a basic one-page app that pulls data from the server via AJAX (done), displays a table of those records (working, but perhaps not done), and enables the user to edit the records from the table in a form on a jQueryUI dialog, preferably without loading more data from the server, as all needed data is currently in the table (this is where I'm messed up,) and then ultimately post just the one record back to the server. As a bonus, I'm hoping to make the form update the content in the table too so that it doesn't need to be reloaded.
My basic viewmodel. I also have some binding code for sorting the columns by clicking on the headers that I've left out as it's irrelevant to the question
function AppViewModel() {
var self = this;
self.records = ko.observableArray(ajaxRecords); //ajaxRecords is a JSON object from the server
/*
THIS SECTION MOVED BELOW FOR EXPLANATION
*/
}
I've been able to get data into the form by using a new viewModel that's passed the object from a click function bind on each row:
self.switchDataToForm = function(clickedItem) {
ko.applyBindings(new FormViewModel(clickedItem), document.getElementById('detailsPage'));
}
But I just feel like that's a bad way of doing things and this should all somehow be achievable through one ViewModel.
I'm interested to see what people say about this. It may be incredibly obvious for some, but I'm just having a hard time wrapping my head around the knockout way of thinking. If this were a jQuery task, it would have been done hours ago, but with quite a bit more markup. I'm really excited about what Knockout JS has to offer the JS dev scene and I want to start using it in practice.
You could try something like this:
function AppViewModel() {
var self = this;
self.records = ko.observableArray(ajaxRecords); //ajaxRecords is a JSON array from the server
self.form = ko.observable();
self.switchDataToForm = function(clickedItem) {
self.form(new FormViewModel(clickedItem));
}
/* another data goes here */
}
function FormViewModel(item) {
var self = this;
self.someProp = ko.observable(item.someProperty);
/* another observables goes here */
}
And html:
<form id="detailsPage" data-bind="with: form">
<input type="text" data-bind="value: someProp" />
...
</form>
You can see how it works in this fiddle: http://jsfiddle.net/Ivan_Srb/MKB8W/2/
Related
Like many, I want to populate a field in a django form based on what is selected in another field. I've read alot of answers with javascript(I struggle in javscript, so that's where I'm having trouble with the exemples), and I almost got it working, but the last step(updating the field itself) isn't working so I'd love some help with that part.
Here are the 2 fields. The first fieldthat gets populated from a query and is located in a div named #merch in the form
merchandise = forms.ModelChoiceField(label='Merchandise', queryset=Merchandise.objects.all(),
merch_price = forms.DecimalField(label='Price', min_value=0, max_value=800,
initial='0.00',decimal_places = 2, max_digits=10)
Upon selection, the second field(div named #price) should then display the price based on the merchandise selected. I created the view for the ajax request:
def check_item_price(request):
if request.method == "GET":
item = request.GET.get('item', '0')#the zero as default doesn't seem to work. To verify
price = Merchandise.objects.get(id = item)
return JsonResponse(price.item_price, safe=False)#is it safe to turn safe off?
and the url
url(r'^_item_price', views.check_item_price, name='_item_price' )
Calling the url manually works great, it returns the price in json format
And here is the javascript that is in the html form. The first part works, upon change it calls the url and a json object is returned, but the second part that should update the second field isn't working. I admit my lack of knowledge in javascript is probably at fault here. I tried many variations based on examples, none worked for me.
<script type="text/javascript">
jQuery(document).ready(function() {
$('#merch').change(function() {
var item = $(this).find(':selected').val();
$.getJSON('/classes/_item_price/',{item:item},
function(data) {
$('#price').append("<option value=" + data.value + "></option>");
});
});
});
</script>
Any pointers on what to fix in the javascript?
Thanks!
After letting it marinate in my head for 2 months, I went back to it and finally made it work. Here is the right code
jQuery(document).ready(function() {
$('#merch').change(function() {
var item = $(this).find(':selected').val();
$.getJSON('/classes/_item_price/',{item:item},
function(data) {
document.getElementById('id_merch_price').value=data;
});
});
});
</script>
First, the ID wasn't precise enough, but also the way of updating it wasn't the right one it seems. I truly feel lost anytime I have to do research on javascript or jquery. So may ways to do the same thing, it's almost impossible to learn for a casual coder like me.
I am trying to get the selected row data form vaadin grid using polymer. But I am not able to get.
Here is the my code:
this.mileageGrid = this.$$("#mileageSectionGrid");
this.mileageGrid.addEventListener('selected-items-changed', function() {
var selected = this.mileageGrid.selection.selected();
this.selectedRowData = this.mileageGrid.getSelectedRow();
this.selectedRowData = this.mileageGrid.selection.getSelectedRow();
if (selected.length == 1) {
detailsOpenIndex = selected[0];
this.callback(detailsOpenIndex);
//this.fire("change-mileage", this.mileage);
}
}.bind(this));
I didn't get any idea after searching from google and vaadin grid document also.
Can anybody tell me, how to get selected row data?
These two lines seem to be incorrect, and look more like something from the Vaadin Java framework API:
this.selectedRowData = this.mileageGrid.getSelectedRow();
this.selectedRowData = this.mileageGrid.selection.getSelectedRow();
I think those are probably causing errors in the browser and any following JavaScript is not working. Check for any errors in your browser’s console.
Otherwise I can’t spot any issues in your code (I’m just not sure if you’ve declared detailsOpenIndex and this.callback outside the visible code).
This app is a Contact Manager. And I want when user is filling the form and click save the contacts which appears to be stored in local storage so I could remove some of them etc. Adding and removing are working but it's not storing.
Here is the app:
http://jsfiddle.net/vpbj32Lh/
The problem in this lines:
self.load = function(){
self.contacts = localStorage.getItem("stored_contacts");
}
self.save = function(){
localStorage.setItem("stored_contacts", self.contacts);
self.contacts=localStorage.getItem("stored_contacts");
console.log(self.contacts.length);
}
If you delete this lines and "data-bind="click: save" in html file. It willbe adding and removing but not saving and loading
I've found a number of things to change in your code.
This is a fixed version:
JS
(function ContactManager(){
// ...
self.contacts = ko.observableArray();
self.addItem = function(){
self.contacts.push(new Contact(self.conName(), self.phone(), self.email(), self.address()));
}
// ...
self.load = function(){
// haven't tested, but probably won't work. I think you'd have to convert your JSON to observables
self.contacts = localStorage.getItem("stored_contacts");
}
self.save = function(){
self.addItem(); // calling it from here, not from your HTML form submit
// you have to convert to JSON to save in localStorage
localStorage.setItem("stored_contacts", ko.toJSON(self.contacts()));
}
ko.applyBindings(self.templateName);
})();
HTML
<form class="addContact" autocomplete="on">
<!-- ... -->
</form>
A couple of observations:
self.contacts = ko.observableArray(self.save); - this doesn't make any sense. You are initializing an observableArray with a function object. You are not even calling the function, you are passing the function. Either way, doesn't make sense here.
<form data-bind="submit: addItem" > and <button data-bind="click: save" type="submit"> - you are binding an event to your click on the button, and another event to the submit of the form, that happens when... well, when you click on the button. This maybe would work with some setup, but wasn't working, so I called the addItem from the save.
localStorage.setItem("stored_contacts", self.contacts); - you are trying to store an array of very complex objects (the contacts), each one full of several other complex objects (the observables) inside localStorage. localStorage, though, only stores strings. So you have to convert your objects to JSON. ko.toJSON is the way to go. More at the docs.
Edit:
This is a working JSFiddle with the saving part. I don't know how does JSFiddle handles the localStorage, but as I told you in the comments on my code in the original answer, your load function is wrong and will have to read the string from the localStorage, parse it to JSON (with JSON.parse(string)) and construct the appropriate objects using your constructor function (Contact). This is pretty easy and you can do by yourself.
Edit 2:
The load function should be something like this (haven't tested):
self.load = function(){
var contactsJSON = localStorage.getItem("stored_contacts"); // a string
var loadedContacts = JSON.parse(contactsJSON); // an array
self.contacts = ko.observableArray(); // an observableArray
for (var i in loadedContacts) {
var loadedContact = loadedContacts[i]; // an object
var newContact = new Contact(/* pass the parameters from loadedContact*/); // a Contact object
self.contacts.push(newContact);
}
}
I'm a newbie to Knockout.js. I implemented the Knockout.js by loading data from ajax source and use foreach loop to create a table of the data. The tutorial i followed is here
http://www.dotnetcurry.com/ShowArticle.aspx?ID=933
My issue here is, due to the nature of my application, I find that the first load is better served from the server side using a grid component and I only want Knockout.js to take care of "Add" row, "Update" a row and "delete" a row.
My question is,
1) how do I replace the "first" load and populate the lookupCollection :ko.observableArray() in the article with the default data in the html table?
2) Related to #1. If the first load, the table layout with data is constructed from the server side, then how do I bind "foreach" to the grid so "add" can be performed on lookupCollection?
Thanks and again, I'm a newbie, I must be missing some key concepts here.
One way would be to pass your initial data into your view model. Since you are using asp.net it would look something like this:
//Dump raw data into javascript variable
var data = #Html.Raw(ViewBag.Data);
function ViewModel(data) {
var self = this;
//Unpack raw data
self.lookupCollection = ko.observableArray(data.lookupCollection);
}
//initialize view model
var viewModel = new ViewModel(data);
ko.applyBindings(viewModel);
I'm having massive problems with databinding to a ListView in a Windows 8 app using Javascript.
Inside the "activated" event on default.js I have written some code to get some data from a web service and push it into an array. This bit works OK and the array is populated.
The problem I have is that the app won't recognise the data. I have this code in a page called inspections.html:
data-win-options="{itemTemplate: select('#imageTextListCollectionTemplate'),
itemDataSource: dataList.dataSource,
layout: {type: WinJS.UI.ListLayout}}
and then in the "activated" event I declare:
var dataList = new Array();
and push the data from the web service into this array. But at runtime I get an error that says something along the lines of "can't find dataSource on undefined dataList".
I've done some of the examples on the MS website and in one of them it creates a dummy dataset and references it from a namespace. I kinda think that what I'm missing here is a namespace too but I don't know what the namespace for default.js is. Or maybe I'm wrong and it's something totally different.
Please help - this is so fundamental (and should be easy) but I can't get my head around it.
Do you want to create datalist in HTML or javascript?
It seems you want to create it from JavaScript. Assuming that you have already pushed your data into array from your webservice, you only need to call:
var dataList = new WinJS.Binding.List(array);
now accessing dataList.dataSource is perfectly valid.
Also, to create the datalist you don't always need an array. You could probably start with an empty list and then keep inserting data directly into the data list from web services, like:
var dataList = new WinJS.Binding.List([]);
dataList.push(value1);
dataList.push(value2);
...
Hope it helps. Let me know if you have any more questions.
If you are getting troubled by assigning datasource in HTML side
Prefer js side like
var list = new WinJS.Binding.List(array here);
listView.itemDataSource = list.dataSource;
by using this you can easily go through the data which you are binding to ListView.