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
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 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>
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'm building a simple email sending form and wanted to make it with ajax. The form submits correctly the first time but if you make any subsequent changes to the text in the form and then submit again then jquery does not pick up on the changes and posts the old data. Whats going on?
<script type="text/javascript">
var $j = jQuery.noConflict();
$j(document).ready(function() {
var submit_url = "mail_submit.php";
var send_email = $j("#sendemail");
send_email.click(function() {
var form = $j("#post");
$j.post(submit_url, form.serialize(), function(data) {
alert(data);
});
});
});
It's working just fine.
Now I would prefer calling the submit event on the form itself, but if you are using a submit input type, remember to return false;
I ran into this problem again.
To solve it you need to use tinyMCE.triggerSave();
The method is outlined here http://maestric.com/doc/javascript/tinymce_jquery_ajax_form
My final code is:
<script type="text/javascript">
var $j = jQuery.noConflict();
$j(document).ready(function() {
var submit_url = "mail_submit.php?action=";
var actions = $j("#sendEmail, a#previewEmail, a#saveEmail, a#updateEmail");
var loading = $j("img#ajax-loading");
var status = $j("span#post-status-display");
actions.click(function() {
tinyMCE.triggerSave();
var form = $j("#post");
var action = $j(this).attr("id");
var update_div = $j("#update-div");
loading.show();
$j.post(submit_url + action, form.serialize(), function(data){
update_div.html(data);
update_div.fadeIn();
loading.hide();
});
});
});
I'm having some problem with passing a javascript array to the controller. I have several checkboxes on my View, when a checkbox is checked, its ID will be saved to an array and then I need to use that array in the controller. Here are the code:
VIEW:
<script type="text/javascript">
var selectedSearchUsers = new Array();
$(document).ready(function () {
$("#userSearch").click(function () {
selectedSearchUsers.length = 0;
ShowLoading();
$.ajax({
type: "POST",
url: '/manage/searchusers',
dataType: "json",
data: $("#userSearchForm").serialize(),
success: function (result) { UserSearchSuccess(result); },
cache: false,
complete: function () { HideLoading(); }
});
});
$(".userSearchOption").live("change", function () {
var box = $(this);
var id = box.attr("dataId");
var checked = box.attr("checked");
if (checked) {
selectedSearchUsers.push(id);
}
else {
selectedSearchUsers.splice(selectedSearchUsers.indexOf(id), 1);
}
});
$("#Send").click(function () {
var postUserIDs = { values: selectedSearchUsers };
ShowLoading();
$.post("/Manage/ComposeMessage",
postUserIDs,
function (data) { }, "json");
});
});
</script>
When the "Send" button is clicked, I want to pass the selectedSearchUsers to the "ComposeMessage" action. Here is the Action code:
public JsonResult ComposeMessage(List<String> values)
{
//int count = selectedSearchUsers.Length;
string count = values.Count.ToString();
return Json(count);
}
However, the List values is always null. Any idea why?
Thank you very much.
You might try changing the controller's action method to this:
[HttpPost]
public JsonResult ComposeMessage(string values)
{
JavaScriptSerializer jass = new JavaScriptSerializer;
AnyClass myobj = jass.Deserialize<AnyClass>((string)values);
...
...
}
I believe that you have to take the JSON data in as a string and do the conversion
manually. Hope it helps. Cheers.