Call any webservice from the same $.ajax() call - ajax

Im creating a usercontrol which is controled client side, it has an javascript-file attatched to it. This control has a button and upon click a popup appears, this popup shows a list of my domain entities. My entities are fetched using a call to a webservice.
Im trying to get this popup usercontrol to work on all my entities, therefore i have the need to call any webservice needed (one per entity for example) with the same $.ajax() call.
I have hiddenfields for the webservice url in my usercontrol which you specify in the markup via a property. So far so good. The problem arise when i need some additional parameters to the webservice (other than pagesize and pageindex). Say for example that one webservice takes an additional parameter "Date".
At the moment i have my parameters set up like this:
var params = JSON.stringify({
pageSize: _this.pageSize,
pageIndex: _this.pageIndex
});
and then i call the webservice like so:
$.ajax({
webserviceUrl,
params,
function(result) {
//some logic
});
});
What i want to do is to be able to add my extra parameters (Date) to "Param" when needed, the specification of these parameters will be done via properties of the usercontrol.
So, bottom line, i have a set of default parameters and want to dynamically add optional extra parameters.
How is this possible?
Thanks in advance.

I know it won't be fast, but something like
var params;
function buildJsonParams(defaultParam1, defaultParam2, optionalParam1, ...)
{
string pString = "params = JSON.stringify({ pageSize: _this.pageSize, pageIndex: _this.pageIndex";
if (optionalParam1 != undefined)
{
pString += ",yourOptionParam: optionalParam1";
}
pString += "});";
eval(pString);
}
or if you don't know ahead of time what the optional parameters are you could use parallel arrays, one being the variable and the other the parameter name and pass those into a buildJSONParams like function to do the same kind of thing only it loops through the 2 arrays that get passed in.

something like this should work
var params = getDefaultParams();
// some condition to determine if extra needed?
params.specialDate = getSpecialDateParam();
// could also be written as params['specialDate'] = getSpecialDateParam();
$.ajax({
webserviceUrl,
JSON.stringify(params),
function(result) {
//some logic
});
});
// ****************************
function getDefaultParams () {
return {
pageSize: _this.pageSize,
pageIndex: _this.pageIndex
};
}

Related

Kendo DataSource Single-Row Read

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)

Using only a controller in FW1 without a view

I have an Ajax request that sends some data to a page and expects back a truthy or falsey value depending on if the data was saved. In my controller I do everything and set the content to a true or false value. I really don't want to create a view just to output 1 variable, so I was wondering if there was a way that I don't have to use a view and only use the controller to output simple strings.
I believe you cannot disable views completely, but there's a pretty simple workaround: you can create one view and use it for many actions.
Let's say we've created the view views/main/ajax.cfm, what could be inside it? Obviously, simplest way is:
<cfoutput>#HTMLEditFormat(rc.response)#</cfoutput>
Personally I like returning JSON, it allows me to have status field, plus data, if needed. This way my view looks like this:
<cfheader name="Content-Type" value="application/json" />
<cfoutput>#SerializeJSON(rc.response)#</cfoutput>
Any way, now in our action we need to do something like this:
// prevent displaying the layout
request.layout = false;
// force special view
variables.fw.setView("main.ajax");
// init response (according to the choice made earlier)
rc.response["status"] = "OK";
rc.response = "";
There's one more gotcha for this. Sometimes you don't want AJAX page to be accessed directly (like opened in browser), or vise-versa -- want to do some debugging when it is.
There's a cool helper isAjax in CFWheels framework, it is easy to port to the FW/1. It could be as simple as adding method like this to controller:
/*
* Check if request is performed via AJAX
*/
private boolean function isAjax() {
return (cgi.HTTP_X_REQUESTED_WITH EQ "XMLHTTPRequest");
}
Actually, that setup code above is also helper method in my apps:
/*
* Set up for AJAX response
*/
private struct function setAjax() {
// prevent displaying the layout
request.layout = false;
// force special view
variables.fw.setView("main.ajax");
local.response["status"] = "OK";
return local.response;
}
So in my action code whole check looks like this, which is pretty compact and convenient:
if (isAjax()) {
rc.response = setAjax();
}
else {
return showNotFound();
}
Hope this helps.
You can't output directly from a Controller: its job is just to call the Model and pass data to the View, so you'll need a view template to do the outputting.
However, you can avoid having to create a separate view for each controller method by using the framework's setView() method. This allows you to override the convention and apply a single view to multiple controller methods. So you could set up a generic "ajax view" and then use it to output the data from any of your controllers:
views/main/ajax.cfm
<!---Prevent any layouts from being applied--->
<cfset request.layout=false>
<!--- Minimise white space by resetting the output buffer and only returning the following cfoutput --->
<cfcontent type="text/html; charset=utf-8" reset="yes"><cfoutput>#rc.result#</cfoutput>
controller.cfc
function init( fw )
{
variables.fw=arguments.fw;
return this;
}
function getAjaxResponse( rc )
{
rc.result=1;
fw.setView( "main.ajax" );
}
function getAnotherAjaxResponse( rc )
{
rc.result=0;
fw.setView( "main.ajax" );
}
You can use onMissingView in you Application.cfc to handle the response for ajax calls, this way you don't need to perform any extra logic in your controller methods.
// Application.cfc
function onMissingView(rc) {
if(structKeyExists(rc, "ajaxdata") && isAjaxRequest()) {
request.layout = false;
content type="application/json";
return serializeJSON(rc.ajaxdata);
}
else {
return view("main/notfound");
}
}
function isAjaxRequest() {
var headers = getHttpRequestData().headers;
return structKeyExists(headers, "X-Requested-With")
&& (headers["X-Requested-With"] eq "XMLHttpRequest");
}
// controller cfc
function dosomething(rc) {
rc.ajaxdata = getSomeService().doSomething();
}
This checks if the request context has an ajaxdata key, and is a genuine ajax request, then returns the serialize data. If it doesn't then it renders the main.notfound view

Is it possible to set a Knockout dependent observable with AJAX POST

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);
});
});
};

Significance of Reflection in AJAX-Based Applications

Ajax and Reflection
I am developing an ajax-based application and wondering, what role reflection plays or might play here?
Probably most importantly I am asking myself, if it would be a good approach to
handle all ajax responses through a single handler,
reflect or interpret the data or error
delegate further processing (e.g. where to inject the html) based upon the analysis.
Is this a budding procedure? What pros and cons come to mind?
Additional clearification
My current implementation, which I am not happy with, looks like this.
Register eventhandlers for user action, which lead to ajax requests.
For each request:
Determine which container is the target for the new content
Validate the ajax response
Pass the result to the appropiate rendering function if everything is as expected
Here is an example
function setGamedayScoringChangeHandlers() {
$("#community").delegate("div.community div.nav", "click", function() {
var orderId = $(this).html();
var communityId = $(this).closest('.communityView ').dashId();
requestGamedayScoringByOrderId(communityId, orderId);
});
}
function requestGamedayScoringByOrderId(communityId, orderId) {
var $targetContainer = $('#community-' + communityId + '-gameday');
$.ajax({
url: '?api=league&func=getGamedayScoringByCommunityIdAndOrderId',
data: {
communityId : communityId,
orderId : orderId
},
success: function(result) {
// custom indicator, that sth. didn't work as supposed
if (result.success === false) {
// a php error couldn't be handled as expected
if (result.error === 'phpRuntimeError') {
// ..
}
// ..
}
else {
renderGamedayScoring(result, $targetContainer);
}
}
});
}
Question
How can this and especially the redundant error checking be simplified? Could Reflection, in a sense of: "Is the response valid? And what does the error message say or data look like?" be a reasonable structure do deal with this? Additionally: Is the "coupling" of the actual ajax request and determing the $targetContainer a "normal" procedure?
Many thanks,
Robson
Yes I think register ajax handler trought one pipe is a good way, because it is more easy to control, you will have less redundant code and less boarding effects. If I look at your code comments it seems the response is not as you expect. I use to do like this for controling a group of ajax request talking with server script. I build one request object like :
// myscript.js
var rqPHP = {
url:'php/dispatcher.php', type:'POST', dataType:'json',
success:function(json, status, jXHR){
//console.log('rqPHP.succes : ', json);
if(!json) return console.warn('[rqPHP.success] json is null');
if(!json.cmd) return console.warn('[rqPHP.success] json.cmd is null');
if(!json.res) return console.warn('[rqPHP.success] json.res is null');
if(json.err && json.err.length){ console.warn('[rqPHP.success errors cmd:'+json.cmd+'] '+json.err);}
// so if no errors, dispatch actions based on original command asked
switch(json.cmd){
case 'loadfile' :
// do whatever with response
break;
case 'savefile' :
// do whatever with response
break;
}
},
error:function(jXHR, status, err){
console.warn('[rqPHP.error] ', status,',',err,',',jXHR.responseText);
}
};
then when use this object trought all my group of different actions and I precise wich action and arguments I pass. I use to ask for a json data so I am able to receive an easy parsing response, so I am able to return the original command asked, and some details on errors that may occured for example, and when I need to fire the request :
// myscript.js
rqPHP.data = {'cmd':'loadfile', 'filename':'file.dat', 'arg2':'other argument'};
$.ajax(rqPHP);
Then an example of one server script that will respond :
// dispatcher.php
$pv = $_POST;
$res = '';
$err = array();
// you check the command asked for :
switch(strtolower($pv['cmd'])){
case 'savefile' :
// do whatever
break;
case 'loadfile' :
// do whatever
if(any error){
$err[] = $loadError;// push error with whatever details you'll retrieve in javascript
}else{
$res = ',"res":"'.$dataLoaded.'"';// format json response so you'll check the var exist
}
break;
}
$jsonRes = '{"cmd":"'.$pv['cmd'].'"'.$res.',"err":"'.implode('|', $err).'"}';// json result
print $jsonRes;
They may be some errors, it is just for the principe, I hope that will help, just some last advices :
you should better use the requestObject.data to pass any arguments instead of setting the url like you did, this is much more easy because jQuery does the properly encoding work
you may use POST so the url stay clean, post vars are 'hidden'
in your case, because you may want to centralize server actions with ONE server script, you should use 'json' as dataType because it is much easier to retrieve details from the response, such errors. You have to distinct the ajax error that is trigger when the url doesn't exist, or access denied, well when the server replies it just can't respond to this request, and distinct the properly response of your server script, I mean the script responds well but it may occur an command error, for example for a 'loadfile' command, the argument fileUrl may be wrong or unreadable, so the action is done but the response will be not valid for you...
If you plan to fire many loads for differents parts (I mean you may don't wait response for an ajax before loading a new one), it should be better to set main success and errors functions for keeping centralization and then build one new request object each time you make a load
function rqSuccess(json, status, jXHR){
// put same checking code as before, then you can also retrieve some particular variables
// here, 'this' should correspond to the request object used for the $.ajax so :
console.log('myTarget is : ', this.myTarget, ' , myVariable is : ', this.myVariable);
}
function rqError(jXHR, status, err){
// put same checking code
}
// then each time you want make one or many independant calls, build a new request object
var myRq = {url:'dispatcher.php',type:'POST',dataType:'json',
success:rqSuccess,
error:rqError,
myTarget:$('#myblock'),// any variable you want to retrieve in response functions
myVariable:'Hello !',// after all it is an object, you can store anything you may need, just be carefull of reserved variables of the ajax object (see jQuery $.ajax doc)
// the data object is sanitized and sended to your server script, so put only variables it will need
data : {'cmd':'loadfile',...}
}
$.ajax(myRq);
// you may load an other independant one without waiting for the response of the first
var myRq2 = {...myTarget:$('#anotherblock'), data:{'cmd':'anotheraction'}...}
$.ajax(myRq2);
As a first step, you should change the error handling on the serverside to produce a non-OK/200 response for error cases, e.g. throw a 500. Then have that handled as an actual error on the clientside, along with other errors, instead of putting it through the success-callback.
That way you can use jQuery's abstractions for global error handling: http://api.jquery.com/ajaxError

Calling multiple views in CouchApp query

I need to search the CouchDB based on several criteria entered in a form. Name, an array of Tags and so on. I would then need various views to index on these fields. Ultimately, all the results will be collated in data.js and provided to mustache.html. Say there are 3 views - docsByName, docsByTags, docsById.
What I don't know is, how to query all these views in query.js. Can this be done and how ?
Or should the approach be of that to write one view that makes multiple emits for each search somehow ?
Thank you.
From what you say I assume you are using Evently, so I will quote from Evently primer:
The async function is the main star, which in this case makes an Ajax request (but it can do anything it wants). Another important thing to note is that the first argument to the async function is a callback which you use to tell Evently when you are done with your asynchronous action. [...] Whatever you pass to the callback function then becomes the first item passed to the data function.
In short: put your Ajax requests in async.js.
As a side note: Evently is only one of the possible choices to write a couchapp and it is not clear if it is maintained. However it works and it is easy to rearrange the code to not use it.
EDIT: here is a sample async function (cut&paste from an old program):
function(cb, e) {
var app = $$(this).app
;
app.db.openDoc('SOMEDOCID', {
error: function(code, error, reason) {
alert("Error("+code+" "+error+"): "+reason);
}
, success: function(doc) {
app.view('SOMEVIEWNAME', {
include_docs: true
, error: function(code, error, reason) {
alert("Error("+code+" "+error+"): "+reason);
}
, success: function(resp) {
resp.doc = doc;
cb(resp);
}
});
}
});
}

Resources