This is my example: enter link description here
How to reload automatically?
beforeProcessing: function (data, status, xhr) {
if (data.rows === '') {
$('#jqGridPreparate').jqGrid('clearGridData');
return false;
}
if (data.inputCol) {
$("td.ui-search-input input#id_prep").val('');
$("td.ui-search-input input#id_opisanie").val(data.inputCol);
var rplc = $.parseJSON($("#jqGridPreparate")[0].p.postData.filters);
for (var i=0; i < rplc.rules.length; i++) {
if (rplc.rules[i].field === 'prep') {
rplc.rules[i].field = 'opisanie';
}
}
$.extend($("#jqGridPreparate")[0].p.postData,{filters:JSON.stringify(rplc)});
$("#jqGridPreparate")[0].triggerToolbar(); // not WORK
}
}
I'm not sure that I full understand what you want to implement. I can guess that you want to apply the filter if some additional information will returned by from the server.
It seems that you implemented some custom agreement between jqGrid and the server about returned data. rows part of the server response should be array of items. In your case the server could set empty string as the value of rows instead. You try to use inputCol property of the server response to force filtering of previously loaded data. You makes some custom modifications of existing filter, you fill some fields of the filter toolbar and finally you try to use triggerToolbar. The code is very unclear and it contains a lot of assumptions which you don't described directly. It's not clear for me whether you want to start local filtering or jqGrid should send new request to the server with modified filter.
In any way, if you want to start some kind of reloading/filtering inside of other callback function, you shuld take in consideration some basic rules. First of all the method triggerToolbar or triggering reloadGrid works synchronously. It means that jqGrid first makes triggerToolbar, which makes reloadGrid, till the end and then will be executed the next line of code after $("#jqGridPreparate")[0].triggerToolbar();. Because of that it's strictly recommended to place all calls of triggerToolbar or reloadGrid inside of setTimeout body. It allows to process the current callback til the end and only then to make reloading. If the response from the server contains your custom information instead of typical jqGrid data then you should return false from beforeProcessing to stop the standard processing.
If you can construct postData.filters then you don't need to use triggerToolbar to apply the filter. Instead of that you need just set search: true parameter of jqGrid additionally and just trigger reloadGrid.
The corresponding code could be about the following:
beforeProcessing: function (data, status, xhr) {
var $self = $(this), p = $self.jqGrid("getGridParam");
if (data.rows === "") {
$self.jqGrid("clearGridData");
return false; // don't process the data by jqGrid
}
if (data.inputCol) {
var i, rplc = $.parseJSON(p.postData.filters);
for (i = 0; i < rplc.rules.length; i++) {
if (rplc.rules[i].field === "prep") {
rplc.rules[i].field = "opisanie";
}
}
p.postData.filters = JSON.stringify(rplc);
setTimeout(function () {
// apply the filter
p.search = true;
$self.trigger("reloadGrid", [{page: 1}]);
}, 50);
return false; // don't process the data by jqGrid
}
}
Related
I have a mobile app that receives a push notification, when it does, I know there is a row that that needs to be updated. I have tried two methods for retrieving just that one:
var row = data_source.get(<id>);
row.dirty = true;
data_source.sync();
This tries to fire an UPDATE, which I could shoe-horn into doing what I want, but it's conceptually wrong.
The other option that I have tried:
data_source.read( { id : <id> } );
Which fires off a READ request, with the ID in options.data. When I try to hook this up, kendo complains about not getting an array back, and when I make the response into an array, it doesn't seem to work either.
How am I supposed to do this? GET it outside the context of the DataSource, and set the relevant parts, and then set the dirty bit to false?
Kendo doesn't do single row read out of the box. If its not feasible to do full read(), you have to do what you proposed. Try following :
1) make your server side read method to accept requests with or without id, without to read all items, with to read your one row.
2) use parameter map together with isPushNotificaton flag to control the read request params
parameterMap: function(data, type) {
if (type == "read") {
if (isPushNotificaton)
return { id : yourId };
else
return { id : 0}; // get all
}
}
3) use requestEnd to decide how to deal with read result
requestEnd: function(e) {
var type = e.type;
if (e.type == 'read') {
// examine the response(by count/add additional flags into response object)
var isFullReadResponse = ...;
if (!isFullReadResponse) {
// DIY
e.preventDefault();
UpdateSingleRow(response, datasource.data());
}
}
}
4) Implement UpdateSingleRow method as you proposed - .."and set the relevant parts, and then set the dirty bit to false", (Refresh a single Kendo grid row)
This is relevant for either client or server side apps using backbone. I am attempting to create a validation function with uniqueness checks to MongoDB or some REST call (depending on environment). Both of these calls are async by nature; however, I think I actually need to make it block here for validation purposes. If I don't return anything the validate function will assume validation passed.
My code currently looks like this on the server side:
isUnique: function (key) {
var dfdFindOne = this.findOne({key: this.get(key)}),
dfd = new Deferred();
dfdFindOne.done(function (err, result) {
console.log(result);
dfd.resolve(true);
});
return dfd;
};
... some stuff here....
I feel like I can do some sort of wait till done functionality here before I return... perhaps not though. I wish backbone provided a callback function or something or accepted some sort of deferred type thing.
validate: function() {
var result = undefined;
if(!this.isUnique(key).done(function(){
result = "AHHH not unique!";
});
return result;
}
A possible solution might be to force mongodb's native node client to call things synchronously. I think I can do the same with rest calls... This is probably a bad solution though.
You could call the ajax request and set async:false in this way the return will have value. However to use async:false is evil because could appear as the browser is locked. For server side maybe there are not always workarounds for set async: false
My recommendation is to use your own validation flow instead of Backbone.validate flow, because the validation flow of Backbone was made thinking for synchronous validations only. You could try something like this:
//Code in your Model
isUnique: function (callback) {
var dfdFindOne = this.findOne({key: this.get(key)});
dfdFindOne.done(function (err, result) {
console.log(result);
callback(result);
});
};
validate: function(callback) {
this.isUnique(callback);
}
//trying to validate before save
model.validate(function(result){
if( result == 'whatexpected'){
model.save();
}
});
Using Knockout 2.0 and MVC3 Razor forms, I am not able to make a dependent observable work when I introduce an ajax method. I have set up a set of observables that are a part of a calculation, and when I return the product of those observables, I am able to set a SPAN tag with the correct result. However, when I try to use the ajax method to handle those observables and return a result, I get unpredictable behavior. First, it appears the ajax POST does not pick up one of the observables when the INPUT fields are updated (var b POSTs to the action method as 0, but then is eventually updated), and then it seems that I am not able to set the result even when it evaluates correctly. It appears there is timing issue with either the observables or the ajax call. Although simply keeping performing the calculation in javascript works fine, my intent is to call ajax methods for more complicated logic. I have removed the call to ko.applybindings from doc.ready(), and also moved the SCRIPT methods to the bottom of the page- this was the only way I found to make this partly functional. My viewModel is set up as follows:
var viewModel = {
a: ko.observable(0),
b: ko.observable(1),
c: ko.observable(2),
// commented this out, since
// the dependent observable will handle this
// d: ko.observable(0)
};
In my dependent observable:
viewModel.d = ko.dependentObservable(function () {
var theResult = 0;
$('.theLabel').css("visibility", "visible");
theResult=viewModel.a() * viewModel.b() * viewModel.c();
// if we return here we get a valid result
return (theResult);
// prefer to call ajax method
// first check to ensure one variable is set
if (viewModel.a() > 0) {
$.ajax("/myCalculation/getResult", {
data: ko.toJSON(viewModel),
type: "post",
context: viewModel,
contentType: "application/json",
success: function (result) {
// can't set visibility here
$('.theLabel').css("visibility", "visible");
// the POST does not pick up some observables, or
// does not the set dependent observable at all
return result;
}
});
}
});
There is quite a bit wrong with the function you have setup.
1.) You are returning from your function before making your AJAX call. The code after your return statement will never execute.
2.) Even if you omit the first return statement, your AJAX call is Asynchronous... which means it will execute in the background and return control to the outer scope immediately. Since you don't have a return statement, then you are going to return undefined.
3.) The comment in your success callback suggests you are expecting the return statement to propagate all the way up to your computed observable. THAT return statement is only scoped to the callback, and not the outer observable. The return value will be used by jQuery, and your observable will long since have returned.
If you want an observable to call an AJAX function you need a seperate value to store the results of the asynchronous call.
Here is a simplified example:
var viewModel = function(){
var $this = this;
$this.a = ko.observable();
$this.b = ko.observable();
$this.results = ko.observable();
//No need to assign this computed observable to a variable
// because the results will be stored in '$this.results'
// we just need this to handle the automatic updates
ko.computed(function(){
var data = {
a: $this.a(),
b: $this.b()
};
$.post("/do/some/stuff", data, function(results){
$this.results(results);
});
});
};
So, I took some code from this Microsoft provided Example which allows me to use the jquery validate unobtrusive library to parse validation error message returned from my server and display them in the UI. They have a video demonstrating this. So, here is the piece of Javascript code I'm using:
$.validator.addMethod("failure", function () { return false; });
$.validator.unobtrusive.adapters.addBool("failure");
$.validator.unobtrusive.revalidate = function (form, validationResult) {
$.removeData(form[0], 'validator');
var serverValidationErrors = [];
for (var property in validationResult) {
//var elementId = property.toLowerCase();
var item = form.find('#' + property);
if (item.length < 1) { item = form.find('#' + property.replace('.', '_')); }
serverValidationErrors.push(item);
item.attr('data-val-failure', validationResult[property].join(', '));
jQuery.validator.unobtrusive.parseElement(item[0]);
}
form.valid();
$.removeData(form[0], 'validator');
$.each(serverValidationErrors, function () {
this.removeAttr('data-val-failure');
jQuery.validator.unobtrusive.parseElement(this[0]);
});
};
So then after a AJAX form post in the handle error function I would do something like this:
$.validator.unobtrusive.revalidate(form, { 'PhysicalAddress.CityName': ['You must select a valid city'] });
Where PhysicalAddress.CityName is the name of my viewmodel property and html input field. So, it knows to put the validation message next to the correct html element.
This works 1 time. Then when they hit submit again and my code calls the unobtrusive.revalidate method again.. it doesnt work. It only shows the validation message one time then after that the validation message disappears for good.
Does anyone have any idea as to why this might be happening?.. I stepped through the revalidate method and no errors were thrown and everything seems like it should work.. but the unobtrusive library for some reason is not re-binding the validation error message.
Thanks
Probably this behavior depends on a known problem of the jQuery validation plugin: dynamically adding new validation rules for elements works just once! Further attempts are rejected because the plugin think they are a duplicated attempt to define the already defined rules.
This is the reason why the $.validator.unobtrusive.parse doesn't work when you add newly created content (when for instance you add a new row to a collection of items). There is a patch for the $.validator.unobtrusive.parse that you might try to apply also to the revalidate function....but it is better to rewrite it from scratch in a different way. The revalidate function usse the validation plugin just to place at the right place all validation errors, then it tries to reset the state of the validation plugin. However, deleting the validator object from the form is not enough to cancel all job done since there is another object contained in the form.data('unobtrusiveValidation'), where form is a variable containing the form being validated...This data are not reset by the revalidate function...and CANNOT be reset since resetting them would cause the cancellation of ALL client side validation rules.
Maybe this problem has been solved in the last version of the validation plugin, so try to update to the last version with nuget.
If this doesn't solve your issue I can pass you an analogous function implemented in a completely different way(it mimics what the server does on the server side to show server side errors). It will be contained in the upcoming version of the Mvc Controls toolkit. However, if you give me a couple of days (I will be very busy for 2 days) I can extract it from there with its dependencies so you can use it. Let me know if you are interested.
Below the code I promised. It expects an array whose elements are:
{
id:id of the element in error
errors:array of strings errors associated to the element
}
It accepts several errors for each element but just display di first one for each element
id is different from the name because . [ ] an other special char are replaced by _
You can transform name into id on the sever with
htmlName.Replace('$', '_').Replace('.', '_').Replace('[', '_').Replace(']', '_');
or on the client in javascript with:
name.replace(/[\$\[\]\.]/g, '_');
function remoteErrors(jForm, errors) {
//////////
function inner_ServerErrors(elements) {
var ToApply = function () {
for (var i = 0; i < elements.length; i++) {
var currElement = elements[i];
var currDom = $('#' + currElement.id);
if (currDom.length == 0) continue;
var currForm = currDom.parents('form').first();
if (currForm.length == 0) continue;
if (!currDom.hasClass('input-validation-error'))
currDom.addClass('input-validation-error');
var currDisplay = $(currForm).find("[data-valmsg-for='" + currElement.name + "']");
if (currDisplay.length > 0) {
currDisplay.removeClass("field-validation-valid").addClass("field-validation-error");
replace = $.parseJSON(currDisplay.attr("data-valmsg-replace")) !== false;
if (replace) {
currDisplay.empty();
$(currElement.errors[0]).appendTo(currDisplay);
}
}
}
};
setTimeout(ToApply, 0);
}
/////////
jForm.find('.input-validation-error').removeClass('input-validation-error');
jForm.find('.field-validation-error').removeClass('field-validation-error').addClass('field-validation-valid');
var container = jForm.find("[data-valmsg-summary=true]");
list = container.find("ul");
list.empty();
if (errors.length > 0) {
$.each(errors, function (i, ival) {
$.each(ival.errors, function (j, jval) {
$("<li />").html(jval).appendTo(list);
});
});
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
inner_ServerErrors(errors);
setTimeout(function () { jForm.find('span.input-validation-error[data-element-type]').removeClass('input-validation-error') }, 0);
}
else {
container.addClass("validation-summary-valid").removeClass("validation-summary-errors");
}
}
function clearErrors(jForm) {
remoteErrors(jForm, []);
}
I'm trying to make two Ajax calls to get data to populate different bits of a web page, and as you'll already know, only the second happens.
So I thought I'd do this:
callAjax1('a'); callAjax2('b');
function callAjax1(data) {
ajax(data);
}
function callAjax2(data) {
ajax(data);
}
function ajax(data) {
// calls XMLHttpRequestObject etc
}
The idea was that instead of calling ajax() twice, now, I'd have two independent instances of ajax that would run independently.
It works .. but only if I put in an alert at the top of ajax() to let me know I've arrived.
So I'm thinking that alert gives the first request time to finish before the second is called. Therefore, I've not managed to separate them properly into separate instances. Is that not possible?
What am I missing?
All the best
J
UPDATE:
I'm thinking this, do I stand a chance?
tParams = new Array (2); // we intend to call ajax twice
tParams[0] = new Array('ajaxGetDataController.php', 'PROJECT', 'id');
tParams[1] = new Array('ajaxGetFileController.php', 'FILE', 'projectId');
<select name='projectSelector' onchange=\"saveData(tParams, this.value);\">\n";
// gets called, twice
function saveData(pParams, pData) // pParams are: PageToRun, Table, Field
{
if (XMLHttpRequestObject)
{
tPage = pParams[0][0]+'?table='+pParams[0][1]+'&pField='+pParams[0][2]+'&pData='+pData;
XMLHttpRequestObject.open('GET', tPage);\n
XMLHttpRequestObject.onreadystatechange = callAjax(pParams, pData);
XMLHttpRequestObject.send(null);
}
}
function callAjax(pParams, pData)
{
if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200)
{
var tReceived = XMLHttpRequestObject.responseXML;
options = tReceived.getElementsByTagName('option'); // fields and their values stored in simplest XML as options
popForm(options, pParams[0][1]); // goes off to use the DOM to populate the onscreen form
pParams.shift(); // cuts off pParams[0] and moves all elements up one
if (pParams.length>0)
{
saveData(pParams, pData);
}
}
}
I would create a ready state variable for the AJAX function:
function ajax(data) {
readyState = false;
// calls XMLHttpRequestObject etc
}
And then check for the ready state before executing the second call:
function callAjax2(data) {
if(readyState == true) {
ajax(data);
readyState = true;
}
}
And make sure to change the readyState back to false after the AJAX calls have executed. This will ensure the first AJAX call has finished executing before the second one tries to fire.