I have an observableArray of options that gets bound to the following:
<select data-bind="options: lookupData.options, optionsText: 'DisplayName', optionsValue: 'Id', value: optionId" />
When I first apply bindings, the options() observable array is empty - an async AJAX call is sent to retrieve these options.
Most of the time, this works perfectly. But if I display the view very quickly, before the AJAX call returns, the dropdown displays with a default option selected, but the options become available. The selected option isn't updated though.
In other words - if I have 'Blue' as the currently selected option, but the select markup is displayed before the AJAX call completes, 'Blue' doesn't get selected after the observableArray of options is populated.
Am I missing some syntax to make this work?
Code:
// getLookupData()
var lookupData = {};
lookupData.colors = ko.observableArray();
$.ajax({
type: "POST",
url: getAllergyRelationshipListUrl.url,
async: true,
data: new Object(),
dataType: "json",
contentType: "application/json"
}).done(function(data, textStatus, jqXhr) {
lookupData.colors(data.Data);
});
return lookupData;
// colorVm
if (vm.colorLookupData == null) {
vm.colorLookupData = getLookupData();
}
ko.applyBindings(vm);
It's a known problem on knockout select. Before your ajax finishes, the value does not exist in options, the options binding enforced your value to be one of options.
This is solved in knockout since version 3.1 with introduction of valueAllowUnset.
Update your binding to:
<select data-bind="valueAllowUnset: true, options: lookupData.options, optionsText: 'DisplayName', optionsValue: 'Id', value: optionId" />
You can read here http://knockoutjs.com/documentation/value-binding.html#using-valueallowunset-with-select-elements
Related
Need help to resolve ajax call issue
In my view page ( working on codeigniter), there is a dropdown and a div
section. Based on dropdown value, data will get change in div section. I am
using ajax call ( to call method in controller) to upload data in div tag on
dropdown change event. Ajax call working fine on first change event of
dropdown but when i select value for second time in dropdown, ajax function
call is not working ( second select and so on).
My code is:
VIEW PAGE =>
$(document).ready(function() {
$("body").on('change','#assettype_id',function(e){ // "assettype_id" is
dropdown id
//e.preventDefault();
var categoryval = $('#assettype_id :selected').val();
$.ajax({
type: 'POST',
cache: false,
url: 'http://my_path/index.php/assetcontroller/assignpc/'+ categoryval, // Based on "categoryval" data will change in div tag
dataType: 'html',
success: function(data) {
$( "#result" ).load( "http://my_path/index.php/assetcontroller/assignpc/"+ categoryval); // "result" is div tag id
$( "#result" ).html(categoryval);
},
});
return false;
});
});
Why ajax call is not working in dropdown 'second time' change event?
You need to wrap the .on('change') event into a function, so it can be called anytime later.
That's because once you have added new html output through Ajax, this html doesn't yet know about your change event!
So the function my_change_event() needs to be re-called, once your Ajax output has been added to DOM with your $( "#result" ).load()
something like this:
$(document).ready(function() {
my_change_event();
});
function my_change_event(){
$( "#assettype_id" ).on( "change", function() {
$.ajax({
type: 'POST',
cache: false,
url: your_url,
success: function(data) {
// do something with data
// html output
my_change_event();
}
});
}
I have the following problem. I m using a custom form for Jqgrid, the problem is that I can t figure it out how can I use different functions for submit button in add/edit/delete. Can you help me? I can use delfunc with succes. How can I add delfunc to the button submit from del form, and the function addfunc to submit button from the form of add.
$('#jqGrid').navGrid("#jqGridPager", {
edit: true,
add: true,
del: true,
refresh: true,
view: false,
addfunc : function(){
var angajat = new Object();
angajat.id = null;
angajat.firstName = "andrei" //jQuery("#jqGrid").jqGrid('getRowData');
angajat.lastName = " chivu " //jQuery("#jqGrid").jqGrid('getRowData');
console.log(angajat);
$.ajax({
type: "POST",
url: "rest/user/add",
data: JSON.stringify(angajat),
contentType: "application/json; charset=utf-8",
dataType: "json",
contentType: "application/json",
success: function (data) {
$("#response").html(JSON.stringify(data));
}
});
},
delfunc : function (id){
$.ajax({
type:"DELETE",
url:"rest/user/delete",
data:JSON.stringify(id),
dataType: "json",
contentType: "application/json",
}).done(function( msg ) {
alert("Content Deleted: " + id);},
jQuery("#jqGrid").trigger("reloadGrid"));
},
editCaption: "Update Employee",
template: template,
//onClick: alert("alaaaaa"),
errorTextFormat: function (data) {
return 'Error: ' + data.responseText
}
},
// options for the Add Dialog
{
addCaption: "Add new Employee",
template: template,
sData: alert("alaaaaa"),
errorTextFormat: function (data) {
return 'Error: ' + data.responseText
}
},
// options for the Delete Dialog
{
caption: "Delete the Employee",
msg: "Are you sure ? ",
beforeSubmit: alert("alaaaaa"),
errorTextFormat: function (data) {
return 'Error: ' + data.responseText
},
});
});
One don't need to use delfunc, addfunc, editfunc or viewfunc in the most cases. The function are replacements for delGridRow, editGridRow and viewGridRow, but to replace the methods which code is not so small one have to understand the code in details.
I try to explain your problem how I understand it. I'll start with the usage of delfunc. What you try to do is calling of URL rest/user/delete using HTTP DELETE. Thus I suppose that you have RESTful services on the backend. To use HTTP DELETE you need to append the id of deleted item to the URL, use DELETE operation and be sure that no other information (like oper parameter) are placed in HTTP body. Thus you can use existing options of delGridRow.
It's important to understand that navGrid just add some buttons in the navigator bar and it calls the methods delGridRow, editGridRow and viewGridRow if the user clicks on the corresponding buttons. The options of navGrid looks like
$("#gridid").jqGrid('navGrid','#gridpager', {parameters},
prmEdit, prmAdd, prmDel, prmSearch, prmView);
(see the documentation). The parameters parts are real options of navGrid and it informs navGrid for example which buttons should be included on the navigator bar. The other options are the options of delGridRow, editGridRow, searchGrid and viewGridRow methods which shoule be used if the user clicks on the corresponding button of navigator bar. To configure the behavior of Delete button we need to specify prmDel parameter. The value of the parameter should be object with the properties and
callbacks of delGridRow method. See the documentation.
In the same way if one uses formatter: "actions" or inlineNav then another buttons will be added and one have to use the corresponding options to specify, which options of delGridRow should be used.
I find that the options of navGrid is difficult to understand. Because of that I introduced in free jqGrid alternative way of specify default options used in jqGrid by delGridRow inside of formDeleting of jqGrid options. Thus the most free jqGrid looks like the demo. It uses formEditing, formViewing, searching options of jqGrid and the call of navGrid is either without any parameters or with the small set of options. Now back to your main problems. See the wiki for more information.
If the main logic is clear then it will be clear how one configure jqGrid to do on Delete exactly what you need. To do this you should specify mtype: "DELETE" option and ajaxDelOptions: {...} to specify other options of Ajax call. To append the id to the URL you can use onclickSubmit or beforeSubmit callbacks (see the answer), but in free jqGrid and can use url defined as function (see the answer) and have more readable code. Thus I suggest you to use formDeleting option with the value
{
mtype: "DELETE",
url: function (rowid) {
return "/rest/user/delete/" + rowid;
},
ajaxDelOptions: { contentType: "application/json" },
serializeDelData: function () {
return "";
},
reloadGridOptions: { fromServer: true },
}
The grid will be reloaded automatically on successful deleting because reloadAfterSubmit: true is default option of delGridRow (see here). The last option reloadGridOptions is helpful in case of usage loadonce: true option of jqGrid. It will force reloading of grid from the server.
In the same way to configure Add and Edit buttons you can use formEditing option of jqGrid with the value
{
url: function (id, editOrAdd) {
return "/rest/user/" + (editOrAdd === "add" ? "add" : "edit");
},
mtype: function (editOrAdd) {
return editOrAdd === "add" ? "POST" : "PUT";
},
serializeEditData: function (postData) {
return JSON.stringify(postData);
},
serializeEditData: function (postData) {
var dataToSend = $.extend({}, postData); // make copy of data
// don't send any id in case of creating new row or to send `0`:
if (dataToSend.id === "_empty") {
delete dataToSend.id; // or dataToSend.id = 0;
}
return JSON.stringify(dataToSend);
},
ajaxEditOptions: { contentType: "application/json" },
reloadGridOptions: { fromServer: true }
}
I have filters outside of jqGrid that should trigger a grid reload. This entry gave me some good insight into how to implement it, using the postData option: How to filter the jqGrid data NOT using the built in search/filter box
Unfortunately the code snippets are fragments, and I cannot figure out what the overall sequence of calls should be. Here's a condensed view of my current approach:
<script>
$(document).ready(function() {
$("#submit").click(function(e) {
e.preventDefault();
myGrid.trigger('reloadGrid');
});
});
var url="${servicesUrl}/projects";
var myGrid = $("#projectList").jqGrid({
url: url,
datatype: 'json',
mtype: 'GET',
// ...
});
</script>
How should I structure the code so that every click of the Submit button will trigger a grid reload? Once I have that sorted out, I'm sure I'll be able to add the posData part, my problem is mostly with the overall sequence of calls. I'm not sure which calls should be inside of the ready() function, and how to call 'reloadGrid' properly. Any help greatly appreciated.
This is what has worked for me: I set a callback on the beforeRequest event which updates the postData property before each request is made.
Note that you will want to put all your jqGrid init code inside the $(document).ready(function(){}); function, otherwise the your table element may not be in the DOM yet
var url="${servicesUrl}/projects";
$(document).ready(function() {
var $table = $("#projectList");
$table.jqGrid({
url: url,
datatype: 'json',
mtype: 'GET',
beforeRequest: function() {
var postData = $table.getGridParam('postData');
//add parameters to postData here
}
// ...
});
$("#submit").click(function(e) {
e.preventDefault();
$table.trigger('reloadGrid');
});
});
I Have problem with my kendoAutoComplete i want to bind two fields to kendoAutoComplete, now I can bind one field name to dataTextField but for another field like id i dont have any other option, Following is my code
var alld="";
function getData(req) {
$.ajax({
url: 'BookingCity.asmx/GetAllCityBus',
contentType: 'application/json; charset=utf-8',
type: 'POST',
dataType: 'json',
minLength: 1,
async: false,
cache: false,
data: "{'prefixText':'" + req + "'}",
success: function(response) {
alld = response.d;
},
error: function(xhr, status) {
alert("error");
}
});
}
$("#totext").kendoAutoComplete({
dataSource: {
read: getData($("#totext").attr("value")),
data: alld
},
minLength: 2,
placeholder: "Select city...",
dataTextField: "Name",
dataTextField:"Id"
});
You can use template to achieve this:
$("#totext").kendoAutoComplete({
template: "#=Name# #=Adress#",
//.. rest of the options
I think you might be looking for dataValueField:"Id"
NOTE:
dataValueField is not used in kendoAutoComplete (my apologies). It was on the demo page on the Kendo UI website by mistake. It seems a dropdownlist or combobox can be used instead.
This is assuming you need to return a value that corresponds with the dataTextField (like the Id).
You can read more about it on the Kendo UI Forums - DataValueField does exist ?
or see this relevant excerpt:
The autocomplete UI widget persists only the selected text. Actually the you can post only the content of the input element. This is the expected behavior. As to the demos, the "dataValueField" is left by mistake and we will fix that for the next release of KendoUI.
In order to achieve your goal, you will need to use dropdownlist or combobox, which persist the selected id.
Regards,
Georgi Krustev
the Telerik team
Why do you want to do this? You can only bind one field to the dataTextField property, so if you want to show two, just add an additional calculated field to your datasource that contains the concatenated values of both fields and bind to that.
I am trying to update a dropdown using knockout and data retrieved via an ajax call. The ajax call is triggered by clicking on a refresh link.
The dropdown is successfully populated when the page is first rendered. However, clicking refresh results in clearing the dropdown instead of repopulating with new data.
Html:
<select data-bind="options: pages, optionsText: 'Name', optionsCaption: 'Select a page...'"></select>
<a id="refreshpage">Refresh</a>
Script:
var initialData = "[{"Id":"231271443653720","Name":"Car2"},{"Id":"439319486078105","Name":"Electronics1.2"},{"Id":"115147185289433","Name":"Product"},{"Id":"145033098963549","Name":"Product2"}]";
var viewModel = {
pages : ko.mapping.fromJS(initialData)
};
ko.applyBindings(viewModel);
$('#refreshpage').click(function() {
$.ajax({
url: "#Url.Action("GetPageList", "FbWizard")",
type: "GET",
dataType: "json",
contentType: "application/json charset=utf-8",
processData: false,
success: function(data) {
if (data.Success) {
ko.mapping.updateFromJS(data.Data);
} else {
displayErrors(form, data.Errors);
}
}
});
});
Data from ajax call:
{
"Success": true,
"Data": "[{"Id":"231271443653720","Name":"Car2"},{"Id":"439319486078105","Name":"Electronics1.2"},{"Id":"115147185289433","Name":"Product"},{"Id":"145033098963549","Name":"Product2"}]"
}
What am I doing wrong?
The problem you have is that you are not telling the mapping plugin what to target. How is it suppose to know that the data you are passing is supposed to be mapped to the pages collection.
Here is a simplified version of your code that tells the mapping what target.
BTW The initialData and ajax result were the same so you wouldn't have noticed a change if it had worked.
http://jsfiddle.net/madcapnmckay/gkLgZ/
var initialData = [{"Id":"231271443653720","Name":"Car2"},{"Id":"439319486078105","Name":"Electronics1.2"},{"Id":"115147185289433","Name":"Product"},{"Id":"145033098963549","Name":"Product2"}];
var json = [{"Id":"231271443653720","Name":"Car2"},{"Id":"439319486078105","Name":"Electronics1.2"},{"Id":"115147185289433","Name":"Product"}];
var viewModel = function() {
var self = this;
this.pages = ko.mapping.fromJS(initialData);
this.refresh = function () {
ko.mapping.fromJS(json, self.pages);
};
};
ko.applyBindings(new viewModel());
I removed the jquery click binding. Is there any reason you need to use a jquery click bind instead of a Knockout binding? It's not recommended to mix the two if possible, it dilutes the separation of concerns that KO is so good at enforcing.
Hope this helps.