I have spent days working on this and really feel dumb. I have been working on demos and samples that never work when I try it locally with my own url. I have a web service that returns results back in json and am just basically trying to call it using dojo and for now just view the results. I took the search google example and just substituted the url and parameters. Now perhaps I still do not understand the basics so:
- io.script.get vs xhrGet
if using cross domain urls it is better to use io.script.get? correct?
now what is the callbackparam? is this the function that is being called in the webservice?
My webservice url is as follows:
http://xxx.xxx.x.xxx/WcfServices/WcfInstance/Service1.svc/RetrievData?query=Word
when I use the following code I get nothing displayed.
function searchGoogle() {
// Look up the node we'll stick the text under.
var targetNode = dojo.byId("rules");
// The parameters to pass to xhrGet, the url, how to handle it, and the callbacks.
var jsonpArgs = {
url: "http://xxx.xxx.x.xxx/WcfServices/WcfInstance/Service1.svc/RetrieveData?",
callbackParamName: "callback",
content: {
query:"dojowords"
},
load: function (data) {
// Set the data from the search into the viewbox in nicely formatted JSON
targetNode.innerHTML = "<pre>" + dojo.toJson(data, true) + "</pre>";
},
error: function (error) {
targetNode.innerHTML = "An unexpected error occurred: " + error;
}
};
dojo.io.script.get(jsonpArgs);
}
dojo.ready(searchGoogle);
Here is what the webservice results look like:
"{\"rules\":[{\"value\":\"AllState\"},
{\"value\":\"Cidade de Goa beach\"},{\"value\":\"Euro 2012\"},
{\"value\":\"Euro2012\"},{\"value\":\"European&Championship\"},
{\"value\":\"Holiday Inn Resort\"},
{\"value\":\"Holiday Inn Resort goa\"},
{\"value\":\"Hotel Goa\"},{\"value\":\"Hyatt Goa\"},{\"value\":\"I buy car\"},...
If I get this part correct then at least I know I have data which I can then bind to a datagrid or chart.
dojo.io.script.get is for all cross domain requests.
xhrGet is for same domain requests.
dojo.io.script.get uses a hack which expects jsonp or json padding as a result. This wraps the response of the web service call inside a self executing function. The function name is the callback name. This has to be wired before the call so it knows what already defined function to call when a response comes back.
All of the arguments are well documented http://dojotoolkit.org/reference-guide/1.7/dojo/io/script.html
My guess as to why your service isn't working is because you wrote the web service and it does not handle jsonp. It is not wrapping its response inside the callbackparamname.
your results should look something like
callback({json});
where callback is whatever you set up in callbackParamName
you can also remove the ? from your url, that should be handled for you.
Related
I am trying to pass a URL as a input parameter to a ApiController from an Angular REST call. The URL comes as a query string (this is a Provider Hosted app in SharePoint, I need the URL to query SP FWIW).
Here is the method signature in the ApiController:
// GET: api/ProjectSite/5
public IEnumerable<ProjectSite> Get(string id)
{
return ProjectSite.GetAllProjectSites(id);
}
And here is where I am making the call in Angular:
var spUrl = "'" + getParameterByName("SPHostUrl") + "'";
var queryUrl = "/api/ProjectSite/" + encodeURIComponent(spUrl);
return $http.get(queryUrl);
This generates a GET request that looks like this:
https://localhost:12345/api/ProjectSite/https%3A%2F%2Fcompany.sharepoint.com%2Fsites%2Fsite_dev%2Fweb
When I do I get 'HTTP 400 (Bad Request)' back. If I stop on a break point in the Angular code and change the input param to a simple string (e.g. 'asdf') the REST call is made and I see the Api is called. If I do not change the string and put a breakpoint inside the Get Api method the breakpoint is not reached, indicating that the code is blowing up somewhere in the route engine.
What I don't get is, while its encoded, the string I am trying to pass in should still be treated as a string, right? I also tried changing the input to Uri but that doesn't appear to work (and Uri isn't listed as a supported input type, anyways).
Anyone know how to pass a URL as input parameter?
Have you tried calling it using a query string?
var queryUrl = "/api/ProjectSite?id=" + encodeURIComponent(spUrl);
I have created a Spring MVC web app.
The app makes a few calls to the controller. These calls are close/open/end game.
I make these calls using Ajax, so I can handle a response on the top of the page.
ajaxPost = function (url, action, id, onSuccess, onError) {
$.ajax({
type: "POST",
url: url + "?" + action + "=" + id,
success: function(response) {
if(onSuccess !== null) {
onSuccess(response);
}
},
error: function(e) {
if(onError !== null) {
onError(e);
}
}
});
};
The question I have is that I'm using 'POST' for the Ajax request, is that correct, or should it be 'PUT'?
My controller has a default URL, and I'm using the param attribute to decide which method to call, as I have many buttons on the page.
#RequestMapping(params = "open", method = RequestMethod.POST)
#RequestMapping(params = "close", method = RequestMethod.POST)
It doesn't sit well with me that I'm using 'POST' for these calls. Maybe it should be 'PUT'...
Any suggestions? Does it matter?
It depends on what your request should do. So there's no general rule that you should use one over the other, they have different use cases.
POST for creating a record.
PUT for updating an existing record (or putting a record at a specified location/id).
See this wikipedia article for the definitions.
One thing to note is that PUT should be idempotent, doing the same PUT request multiple times should ideally produce the same result as doing a single PUT request. However, POST is not idempotent, so doing several POST requests should (or will) create multiple new records.
So after having read this you should check what your method does, and select the corresponding request method.
Both PUT and POST may create a new record; PUT may also update/change an existing record.
The difference between POST and PUT is that PUT is expected to address the record with it's ID, so that the server knows what ID to use when creating (or updating) the record, while POST expects the server to generate an ID for the record and return it to the client after the record has been created.
Thus, a POST is addressed to the resource as a collection: POST /resource, while PUT is addressed to a single item in the collection: PUT /resource/1
Use POST. Always use POST, unless you're absolutely rock-solid certain that PUT is properly supported by your hosting system.
Not sure if SFDebug is any help in this situation. I am making an ajax post using jQuery. Which retrieves JSON data in my action URL and then makes a call to the Model method that executes the action. The part until my action URL, and the jQuery call to it work fine. With the data transmitted from the client to the server well received and no errors being made.
It is the part where it calls the method on the Model that is failing. My jQuery method looks like this:
$.post(url, jsonData, function(servermsg) { console.log(servermsg); }) ;
My server action is like this
public function executeMyAjaxRequest(sfWebRequest $request)
{
if($request->isXmlHttpRequest())
{
// process whatever
$servermsg = Doctrine_Core::getTable('table')->addDataToTable($dataArray);
return $this->renderText($servermsg);
}
return false;
}
The method of concern in the Table.class.php file looks like this:
public function addDataToTable($dataArray)
{
// process $dataArray and retrieve the necessary data
$data = new Data();
$data->field = $dataArray['field'];
.
.
.
$data->save();
return $data->id ;
}
The method fails up here in the model, when renderText in the action is returned and logged into the console, it returns the HTMl for SFDEBUG. Which indicates that it failed.
If this was not an Ajax call, I could debug it by seeing what the model method spat out, but this is a little tedious with Ajax in the mix.
Not looking for exact answers here, but more on how I can approach debugging ajax requests in a symfony environment, so if there are suggestions on how I can debug this, that would be great.
You must send cookie with session ide key via ajax
(Assuming you have XDEBUG configured on the server)
In order to trigger a debug session by an AJAX request you have to somehow make that request to send additional URL parameter XDEBUG_SESSION_START=1. For your example:
$.post(url + '?XDEBUG_SESSION_START=1', jsonData, function(servermsg) { console.log(servermsg); }) ;
You can also trigger it via cookie, but appending URL parameter usually easier.
This a screen shot of what I get when I call my ajax request:
How do I run only the task, without printing the whole page? This is my ajax call:
$.ajax
({
type: "POST",
url: "index.php?option=com_similar&task=abc",
data: {
id: id,
name: name,
similar_id: similar_id,
},
cache: false,
success: function(html)
{
$("#flash").fadeOut("slow");
$("#content"+similar_id).html(html);
}
});
});
$(".close").click(function()
{
$("#votebox").slideUp("slow");
});
});
Don't go with exit or die, Joomla! has it's nice way of dealing with this stuff.
The answers below are tested in Joomla! 2.5 & 3 (for 1.5. may work as well).
General
Your URL for the task needs to look like this:
index.php?option=com_similar&task=abc&format=raw
You than create the controller which will use the view, let's say Abc, which will contain the file view.raw.html (identical to a normal view file).
Below you have the code for generate a raw HTML response:
/controller.php
public function abc()
{
// Set view
JRequest::setVar('view', 'Abc');
parent::display();
}
/views/abc/view.raw.php
<?php
defined('_JEXEC') or die;
jimport('joomla.application.component.view');
class SimilarViewAbc extends JView
{
function display($tpl = null)
{
parent::display($tpl);
}
}
/views/abc/tmpl/default.php
<?php
echo "Hello World from /views/abc/tmpl/default.php";
Note: This is the solution I would use if I had to return HTML (it's cleaner and follows Joomla logic). For returning simple JSON data, see below how to put everything in the controller.
If you make your Ajax request to a subcontroller, like:
index.php?option=com_similar&controller=abc&format=raw
Than your subcontroller name (for the raw view) needs to be abc.raw.php.
This means also that you will / may have 2 subcontrollers named Abc.
If you return JSON, it may make sense to use format=json and abc.json.php. In Joomla 2.5. I had some issues getting this option to work (somehow the output was corrupted), so I used raw.
If you need to generate a valid JSON response, check out the docs page Generating JSON output
// We assume that the whatver you do was a success.
$response = array("success" => true);
// You can also return something like:
$response = array("success" => false, "error"=> "Could not find ...");
// Get the document object.
$document = JFactory::getDocument();
// Set the MIME type for JSON output.
$document->setMimeEncoding('application/json');
// Change the suggested filename.
JResponse::setHeader('Content-Disposition','attachment;filename="result.json"');
echo json_encode($response);
You would generally put this code in the controller (you will call a model which will return the data you encode - a very common scenario). If you need to take it further, you can also create a JSON view (view.json.php), similar with the raw example.
Security
Now that the Ajax request is working, don't close the page yet. Read below.
Don't forget to check for request forgeries. JSession::checkToken() come in handy here. Read the documentation on How to add CSRF anti-spoofing to forms
Multilingual sites
It may happen that if you don't send the language name in the request, Joomla won't translate the language strings you want.
Consider appending somehow the lang param to your request (like &lang=de).
New in Joomla 3.2! - Joomla! Ajax Interface
Joomla now provides a lightweight way to handle Ajax request in a plugin or module. You may want to use the Joomla! Ajax Interface if you don't have already a component or if you need to make requests from a module your already have.
If you just want to include the response output in some HTML element, append format=raw to your URL as mentioned above. Then you could have a controller function like this:
function abc(){
//... handle the request, read variables, whatever
print "this is what I want to place in my html";
}
The AJAX response will output everything you printed / echoed in the controller.
I posted this earlier on wordpress.stackexchange.com. However, never got a reply. Hence, trying my luck here.
I am hereby providing a detailed description of what I need and what I have done for this issue of mine. I am open to any workable solution around what I have done or maybe new suggestions.
I need to make use of user data that is retrieved using the following:
$user_data = get_user_by('login', get_query_var('user_login'));
The above code uses the username passed as a query_var in the URL. All works until here.
I make use of the above code in several Ajax callbacks (handled by admin-ajax.php) on single page load. Since, the site is targeted as a high volume site. All these Ajax requests lead to several database query for the same data. So the obvious idea to save some database queries is to pass the data to a global variable like below:
$_GLOBALS['user_data'] = get_user_by('login', get_query_var('user_login'));
And then use the same in the Ajax callbacks. Here's problem. None of the Ajax callback functions see the global $user_data variable. Before you ask, yes I have declared the global inside callback as well.
So, the obvious answer would be: why not use wp_localize_script and pass the $user_data to the Ajax callback via javascript like bellow:
In PHP:
wp_localize_script('jquery', 'ajaxVars', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'user_data' => $user_data));
In Javascript:
jQuery.ajax({
url: ajaxVars.ajaxurl,
type:'POST',
async: false,
cache: false,
timeout: 10000,
data: 'action=ajax_callback&user_data=' + ajaxVars.user_data,
success: function(value) {
alert(value);
},
error: function() {
alert(error);
}
});
However, this poses two questions:
Can an object that get_user_by('login', get_query_var('user_login')); returns be handled by wp_localize_script()?
If the answer to above question is yes, then would it not pose a security threat since the object would contain sensitive user information?
To overcome the global variable being not available to Ajax callbacks, I declared it directly in functions.php (without wrapping it inside a function). However, get_query_var('user_login') does not return any data when used directly inside functions.php making this futile exercise (You have to add it inside a function and call it via an action).
So, the question remains: how do I stop making $user_data = get_user_by('login', get_query_var('user_login')); calls for every Ajax request? Or is there a way I could get get_query_var('user_login') to work inside functions.php directly (without wrapping it inside a function) or a workaround?
Or maybe some completely new out of the box thinking?
All these Ajax requests lead to several database query for the same
data. So the obvious idea to save some database queries is to pass the
data to a global variable like below:
$_GLOBALS['user_data'] = get_user_by('login', get_query_var('user_login'));
And then use the same in the Ajax callbacks.
Each request that your application receives, AJAX or otherwise, lives completely in isolation: the code handling the requests does not share any state between them (besides whatever is persisted to a database). A global (or constant, or property, or variable, or anything) you define in one request will never be available to subsequent requests unless you store it somewhere.
There are a number of approaches to reducing the number of queries these requests are creating. One would be to retrieve the required user data on page load and pass it to subsequent requests. E.g.:
var user = 'someUser';
$.get('user-data.php?user=' + user, function(user_data) {
$.ajax('some-endpoint.php', {
type: 'POST',
data: { user: user_data },
success: function() { /* ... */ }
});
$.ajax('some-other-endpoint.php', {
type: 'POST',
data: { user: user_data },
success: function() { /* ... */ }
});
});
Alternatively, if it's the currently logged in user you're working with you can write their details to a JavaScript object on initial page load for use later.
var userData = <?php get_currentuserinfo(); echo json_encode($current_user); ?>;
Another option would be to ensure that the get_user_by results were being cached, either by Wordpress, MySQL or some other caching layer. That way it doesn't particularly matter how many times your code calls the method.
In general if lots of your endpoints are sharing functionality, you could probably stand to refactor some of that code.