I am trying to pull data from a database using an ajax call and then put that data in a view model which will then be bound to a table using knockout. Here is my code:
<script>
$(document).ready(function () {
var LoadFiles = '#Url.Action("Files", "Home")';
var HomeModel = function () {
debugger
var self = this;
self.rows = ko.observableArray([]);
$.ajax({
method: "POST",
url: LoadFiles,
success: function (data) {
alert('inside ajax call');
self.rows = JSON.parse(data);
},
error: function (data) {
alert('error');
}
});
}
alert('outside ajax call');
var model = new HomeModel();
debugger
ko.applyBindings(model);
});
</script>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
However, the problem is that my view model.rows is empty because as I discovered through some alert("") calls, the `alert('outside ajax call'); is called first, then the page loads and binding is applied, then the alert('inside ajax call'); is called. I don't understand how this is possible especially since I call var model = new HomeModel() before the bindings are applied. How can I ensure that the self.rows of my HomeModel are populated before the page loads to ensure my .rows are not empty?
UPDATE:
Thanks to #RoyJ, this now works as expected:
<script>
$(document).ready(function () {
var LoadFiles = '#Url.Action("Files", "Home")';
var HomeModel = function () {
debugger
alert('above');
var self = this;
self.rows = ko.observableArray([]);
$.ajax({
method: "POST",
url: LoadFiles,
success: function (data) {
alert('inside ajax call');
self.rows(JSON.parse(data))
alert('below');
},
error: function (data) {
alert('error');
}
});
}
alert('outside ajax call');
var model = new HomeModel();
debugger
ko.applyBindings(model);
});
</script>
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
Related
i am using the knockout js, i am finding diffcult to bind the data while in ajax get method, i have created model, viewModel, and ajax function, i have the ajax method in the same js file where i have created viewModel i am calling the ajax on page load and trying to bind my html with konckout js, i am getting the error userModel is undefined if i give this.name = ko.observale(result[0].name) before the ajax call, after the ajax called it give name is undefined need help
<html>
<head>
<script src="js/jquery1.9.js"></script>
<script src="js/knockout-3.3.0.js"></script>
<script src="js/knockout.mapping.js"></script>
<script src="model/usermodel.js"></script>
</head>
<body>
<div>
<h1><span data-bind="text:user().name"></span></h1>
<h1><span data-bind="text:user().userName"></span></h1>
</div>
<script src="ViewModel/userDetailsViewModel.js"></script>
</body>
</html>
////Model////
function userModel(result) {
var self = this;
this.name = ko.observable(result[0].name); /// give me error undefined before the ajax call and after ajax call i get the value in result
this.userName = ko.observable();
}
/////View Model////
var result
var userDetailsViewModel = function(result) {
self = this;
self.user = ko.observable(new userModel(result));
};
var mainUserDetailsViewModel = new userDetailsViewModel(result);
ko.applyBindings(mainUserDetailsViewModel);
////ajax called on the page load ////
$.ajax({
type: "POST",
dataType: "json",
url: baseUrl + 'api/xx/xxx',
data: jason.strigfy(),
success: function(data) {
result = data;
////I am getting in result json data object 0=["name":"nnnn","Username":"mmmmmm"],
//// i am passing this result to ViewModel and to Usermodel Constructor//
mainUserDetailsViewModel.user(new userModel(result));
},
error: function(error) {
jsonValue = jQuery.parseJSON(error.responseText);
//jError('An error has occurred while saving the new part source: ' + jsonValue, { TimeShown: 3000 });
}
});
Here is my suggestion to have a clean nested view model.
Example : https://jsfiddle.net/kyr6w2x3/28/
function UserViewModel() {
var self = this;
self.UsersList = ko.observableArray([]);
self.GetUsers = function() {
$.ajax({
type: "POST",
dataType: "json",
url: baseUrl + 'api/xx/xxx',
data: jason.strigfy(),
success: function (data) {
//Here you map and create a new instance of userDetailVM
self.UsersList($.map(data, function (user) {
return new UserDetailViewModel(user);
}));
}
});
}
//call to get users list when the VM is loading or you can call it on any event on your model
self.GetUsers();
}
function UserDetailViewModel(data){
var self = this;
self.Name = ko.observable(data.name);
self.UserName = ko.observable(data.username);
}
ko.applyBindings(new UserViewModel());
View :
<h1 data-bind="foreach: UsersList">
<div data-bind="text: Name"></div>
<div data-bind="text: UserName"></div>
</h1>
I am using knockoutJs 3.3.0. In My application I have common javascript file which is reffered all over the application. apart from that I'll be having individual Js files for each page.
So I have two view Models, one is in common and another is page-level viewModel page level one view model. and all the functions of my both Js files are ajax.
I need to bind them in view.
This is my Common ViewModel
var App = function () {
var self = {};
self.FP = ko.observable($("#fpTag").val());
self.UserName = ko.observable($("#StoreValues").val());
self.Enterprise = ko.observable($("#fpIdentifier").val());
self.UpdateFP = function () {
$.ajax({
url: "/Home/createDeal",
type: "POST",
data: { tag: self.FP() },
success: function (data) {
self.FpData($.parseJSON(data));
//return result;
},
error: function (data) {
//return result;
}
});
}
return self;
}
ko.applyBindings(new App());
and this is my PageLevel Js
var Discovery = function() {
var self = {};
var application = new App();
self.KeyWords = ko.observable();
self.GetSearchKeywords = ko.computed(function () {
var data = application.FpData();
if (data != null) {
$.ajax({
url: "/Home/GetSearchKeywords",
type: "POST",
data: { tag: application.UserName(), EnterpriseId: application.Enterprise(), StoreType: "SINGLE", offset: 1 },
success: function (res) {
self.KeyWords($.parseJSON(res));
},
error: function (res) {
}
});
}
});
return self;};ko.applyBindings(new Discovery());
I My view How can I refer the Value as I need all values from both ViewModels.
In My view:
<tbody data-bind="foreach: $root.KeyWords()">
<tr>
<td data-bind="text: keyword"></td>
<td data-bind="text: App().FormatDate(createdOn)"></td>
<td data-bind="text: ip"></td>
</tr>
</tbody>
<input data-bind="value: App().FP()"/>
How can I achieve this..?
UPDATE
Here is the link which I found Helpful. multiple viewmodels communication
This is (IMHO) not possible, one can bind only one model to a specific element.
I would try to make one model object a property of the other one.
You should 'composite' the two viewModels together:
JS:
var App = function (pageVm) {
var self = {};
if (typeof pageVm !== 'undefined') {
self.pageVm = pageVm;
}
self.FP = ko.observable($("#fpTag").val());
self.UserName = ko.observable($("#StoreValues").val());
self.Enterprise = ko.observable($("#fpIdentifier").val());
self.UpdateFP = function () {
$.ajax({
url: "/Home/createDeal",
type: "POST",
data: { tag: self.FP() },
success: function (data) {
self.FpData($.parseJSON(data));
//return result;
},
error: function (data) {
//return result;
}
});
}
return self;
}
var pageVm = new Discovery();
ko.applyBindings(new App(pageVm));
Now your App bindings work without modification, and you can access your page-specific VMs through the App.pageVm attribute.
I prefer this, typically, rather than binding each VM to a different DOM node (also an option) because often one node may be nested inside the other which can make that difficult.
For some reason I want to call knockout method in jQuery.
Knockout viewModel is already binding. I don't know how to call it in jQuery.
Here is my code.
$(document).ready() {
form_submit();
}
function form_submit() {
var form = $('#form');
var serializedData = form.serialize();
$.get("{% url 'search:search' %}", serializedData, function(response) {
AppViewModel.count(response.count); // I tried this, it says undefined is not a function
//Then I tried:
var newModel = new AppViewModel();
newModel.count(response.count); //No errors, but UI doesn't change. I know it's because I'm not binding it. But I don't think I can binding it, because only 1 ko.binding allowed.
}
function AppViewModel() {
var self = this;
self.count = ko.observable(count); //Assume I initially assigned some value to count.
//some other code below not related to this question.
}
ko.applyBindings(new AppViewModel());
Hope someone can help. Thanks!
Why don't you assign the result of calling new AppViewModel to a variable before applying the bindings on it? Then you can reference that variable inside your jQuery get callback.
Something like the following:
$(document).ready(function() {
form_submit();
});
var vm = new AppViewModel();
function form_submit() {
var form = $('#form');
var serializedData = form.serialize();
$.get("{% url 'search:search' %}", serializedData, function(response) {
vm.count(response.count);
});
}
function AppViewModel() {
var self = this;
this.count = ko.observable(count);
}
ko.applyBindings(vm);
You can also just bind to your form's submit event which should simplify some of your code organization.
For example, in the following HTML, I'm binding to my form's submit event:
<div id="myHTML">
<form data-bind="submit: myFormHandler">
<!-- form inputs here -->
</form>
</div>
Then in my view model, I'd have the following:
function AppViewModel() {
this.count = ko.observable();
this.myFormHandler = function(formElement) {
var self = this;
var serializedData = $(formElement).serialize();
$.get("{% url 'search:search' %}", serializedData, function(response) {
self.count(response.count);
});
}
}
$(document).ready(function() {
var vm = new AppViewModel();
ko.applyBindings(vm, $("#myHTML")[0]);
});
Note that in the above example, I'm scoping my bindings to the myHTML div.
I am trying to fetch data from restful wcf service in page load and bind to drop down which is not working.
function CreateItem(name, value) {
var self = this;
self.itemName = ko.observable(name);
self.itemValue = ko.observable(value);
};
function AppViewModel() {
var self = this;
self.titleList = ko.observableArray();
self.load = function () {
alert("click fired");
$.ajax({
url: "https://mydomain/RestfulService/Service1.svc/CreateData?name=venkat",
type: "POST",
cahce: false,
async: false,
data:'',
dataType: "jsonp",
success: function (data) {
for (var i = 0; i < data.length; i++) {
self.titleList().push(new CreateItem(data[i].Description, data[i].TitleID));
}
alert("success " + data);
},
error: function (error) {
alert("failed " + error);
}
});
};
};
<div>
<select data-bind="options: titleList(), optionsText: 'itemName', optionsValue: 'itemValue', value: selectedTitleValue, optionsCaption: 'Please choose'"></select>
</div>
<script type="text/javascript">
$(document).ready(function() {
var model = new AppViewModel();
model.load();
ko.applyBindings(model);
});
</script>
The issue is, knockout array is populating in load function correctly but drop down is not refreshing updated data. I am not understanding where is the problem. Please give inputs.
Replace:
self.titleList().push(new CreateItem(data[i].Description, data[i].TitleID));
with
self.titleList.push(new CreateItem(data[i].Description, data[i].TitleID));
The reason is self.titleList() returns the underlying array, when you push data to it, Knockout is unaware of the changes and does not notify the views.
What is the simplest method of posting a form to the server when clicking the submit button using knockout.js?
This is what I have currently but it is not posting. What is broken with my saveForm function?
// Here's my data model with save option
var self = this;
var viewModel;
$.getJSON('#Url.Content("~/api/myData")', function (data) {
viewModel = ko.mapping.fromJS(data);
self.save = function (form) {
alert("Could now transmit to server");
};
viewModel.saveForm = function () {
var jsonData = ko.mapping.toJSON(viewModel);
$.ajax({
type: "POST",
url: '#Url.Content("~/api/myData")',
data: jsonData
});
};
ko.applyBindings(viewModel);
});
<button type="submit">Save</button>
probably worth putting the line
debugger;
before
viewModel = ko.mapping.fromJS(data);
and checking what happens to viewModel in firebug. "viewModel = ko.mapping.fromJS(data);" will replace everything in viewModel with the json you are loading. This includeds your function saveForm