I tried to use withParameters method on query like that:
query.withParameters({ includeLocation: true })
Unfortunately my parameter was not added to url. I use breeze.debug.js and I've found this line in it
//queryOptions = __extend(queryOptions, this.parameters);
Is that a bug ? Is withParameters support taken out ? Or do I do something wrong ?
I use oData
When .withParameters is used, the parameters are added to the URL by the data service adapter, not by the Breeze core. That's why that line is commented out. This allows the parameters to be encoded differently, depending upon the backend that is used.
That's great, but the data service adapter for OData that ships with Breeze 1.4.8 does not handle .withParameters. The WebApi adapter does, but not the OData adapter. We'll make sure it's added in a future release. In the meantime, you can continue to use your workaround.
This oversight/omission is partly because we don't know any OData services that handle custom parameters. If I may ask, what OData service are you using?
It looks like this will hopefully be fixed soon: https://github.com/Breeze/breeze.js/issues/19.
In the meantime, you can use this code as a workaround (kudos to the author of this pull request):
var odataAdapter = breeze.config.getAdapterInstance('uriBuilder', 'OData');
var origBuildUri = odataAdapter.buildUri;
odataAdapter.buildUri = function (entityQuery, metadataStore) {
var uri = origBuildUri(entityQuery, metadataStore);
//Add custom query option support to webapi odata.
//See https://github.com/Breeze/breeze.js/issues/19
if (entityQuery.parameters !== null && typeof entityQuery.parameters === 'object'
&& Object.keys(entityQuery.parameters).length)
{
var queryParams = {};
for (var param in entityQuery.parameters) {
if (/^([^\$].*)$/.test(param)) {
var val = entityQuery.parameters[param];
if (typeof val == 'string') val = "'" + val + "'";
queryParams[param] = val;
}
}
//get the uri without the resourceName
var resourceName = entityQuery.resourceName;
uri = uri.substr(resourceName.length + 1);
//build the new uri
uri = resourceName + toQueryOptionsString(queryParams) + '&' + uri;
}
//Copied from breeze.js OData adapter
function toQueryOptionsString(queryOptions) {
var qoStrings = [];
for (var qoName in queryOptions) {
var qoValue = queryOptions[qoName];
if (qoValue !== undefined) {
if (qoValue instanceof Array) {
qoValue.forEach(function (qov) {
qoStrings.push(qoName + "=" + encodeURIComponent(qov));
});
} else {
qoStrings.push(qoName + "=" + encodeURIComponent(qoValue));
}
}
}
if (qoStrings.length > 0) {
return "?" + qoStrings.join("&");
} else {
return "";
}
}
return uri;
};
Related
In my view, I have a javascript function to handle a select event on a pie chart. The function is shown below:
function selectHandler() {
var selectedItem = visualization.getSelection()[0];
if (selectedItem) {
var val = data.getFormattedValue(selectedItem.row, 0);
location.href = '/Tickets';
}
}
Currently I am on the Home Controller in the Groups View. I want to navigate to the Index View of the Tickets Controller while passing the selected value from the javascript variable "val". How would I go about doing this?
Are you intending to manually navigate the user?
If you're looking for a redirect JavaScript way, then you would do something as simple as...
location.href = '/Tickets?value=' + val;
Now this may not work for everything. For example, if location.href already contains a '?', and you need to maintain that context, then you need to use '&'. Maybe your app lives in a Virtual Directory.
You might do something like...
var newUrl = location.href;
if (newUrl.indexOf('?') > -1)
newUrl += '&';
else
newUrl += '?';
newUrl += val;
This allows you maintain any existing context as well.
If you expect the ticket to already be defined, you might need to remove that from the query string, if it already exists.
In that case then you might want to do something like...
var params = location.search.substring(1).split('&'),
paramToRemove, indexOfValue,
hasSearch = false,
param;
for (var i = 0, len = i; i < len; i++)
{
param = params[i];
indexOfValue = param.indexOf('value');
hasSearch = param.indexOf('?') === 0;
if (indexOfValue === 0 || (indexOfValue === 1 && hasSearch ))
{
paramToRemove = params[i];
break;
}
}
var newUrl = location.href;
// Remove old value
if (paramToRemove) newUrl = newUrl.replace(paramToRemove, hasSearch ? '?' : '');
// Add proper search char
if (newUrl.indexOf('?') > -1)
newUrl += '&';
else
newUrl += '?';
// Add new value
newUrl += val;
location.href = '/Tickets?val=' + val;
//On page load the server will generate the URL for you.
var ticketURL = '#Url.Action("Index", "Tickets")';
//Append the value to the URL
ticketURL = ticketURL + '?val=' + val;
//Do your stuff!
Since, you are calling Controller methods from javascript. You should make an POST ajax call to Ticket Controller and passing Action method name also.
Your code would be like this:
return $.post('/Ticket(ControllerName)/Index(method name)/',parameters here);
Inside API Controller, Index method will accept the same param which we are passing from our javascript.
ActionResult Index(parameter){...}
As it is, ExtJS 4.1 with a Rest proxy and a Json reader asks for a URI like this (urlencoded, though):
http://localhost:8000/api/v1/choice/?filter=[{"property":"question_id","value":2}]
my server wants filter requests to look like:
http://localhost:8000/api/v1/choice/?question_id=2
I've looked at the filterParam config for the proxy, but it doesn't seem relevant. Is there a practical way to achieve the request URI that the server needs?
Following ain't pretty, but it works. Now to fix the damn Store...
/**
* Customized to send ../?prop=val&prop2=val2 urls.
*/
buildUrl: function(request) {
var url = this.url;
var filters = eval(request.params['filter']);
if (filters) {
delete request.params['filter'];
url += '?'
for (var i = 0; i < filters.length; i++) {
var filterString = filters[i].property + "=" + filters[i].value;
if (url.slice(url.length-1) === '?') {
url += filterString;
} else {
url += '&' + filterstring;
}
}
};
return url;
},
There is no simple (easy) way. You will have to extend existing Proxy class. Take a look at the source code for Ext.data.proxy.Proxy and Ext.data.proxy.Server. Start with looking at functions getParams and buildUrl
I have some trouble appending a token to the backbone url query string and hope you guys could help me out here. Three things to know,
There is a rest api that expects a token with each request
An nginx backend that does auth, serves the backbone app + proxy req to the api under /api
i'm a new to javascript + backbone :/
The backbone app actually reads the token from a cookie and I need to append this to the request url everytime backbone makes a call. I see this can be done by overriding backbone sync. but it troubles me in a few different things. like, this is what I do
console.log('overriding backbone sync');
var key ="token";
Backbone.old_sync = Backbone.sync
Backbone.sync = function(method, model, options) {
if (method === 'read') {
if (!(model.url.indexOf('?key=') != -1)) {
model.url = model.url + '?key=' + key;
}
} else {
old_url = model.url();
if (!(old_url.indexOf('?key=') != -1)) {
model.url = function() {
return old_url + '?key=' + key;
}
}
}
Backbone.old_sync(method, model, options);
};
model.url was returning a function when its not a "read" method and didn't know how to handle it well and the other trouble is when a consecutive request is made, the token is added twice. I tried to remove it with that indexOf stuff with no luck.
Is there a better way to do this ?
I don't think you need to override sync at all:
var globalKey = 'key123';
var urlWithKey = function(url, key) {
return function() {
return url + "?key=" + key;
};
};
var MyModel = Backbone.Model.extend({
url: urlWithKey('/my/url/', globalKey)
});
If you now create an object and save it, a POST request to my/url/?key=key123 is sent.
I guess you could also override the url method if this is the behavior you need for all of your Backbone models.
A general note: in Backbone most parameters, such as url can be a function or a value. I don't know why in your example it was a function once and a value in another case, but you always must be able to handle both ways if you override some of the internal functions. If you look at Backbone's sourcecode you will see that they use getValue to access these parameters:
var getValue = function(object, prop) {
if (!(object && object[prop])) return null;
return _.isFunction(object[prop]) ? object[prop]() : object[prop];
};
Update: Overloading the url method for all models could work like this:
var globalKey = 'key123';
(function() {
var baseUrl = Backbone.Model.prototype.url;
Backbone.Model.prototype.url = function() {
return this.baseUrl + "?key=" + globalKey;
};
})()
var MyModel = Backbone.Model.extend({
baseUrl: '/my/url/'
});
You could also leave the regular Backbone.Model as it is, and create your own base class. See http://documentcloud.github.com/backbone/#Model-extend for details.
Just set your URL like so:
url : function() {
return "/my/url" + this.key;
}
In your overridden .sync, you only need to set the key property.
I need to make an Ajax request, but its response may vary and it's decided on the server side.
Is there any way to know what type the response is?
It may look similar to:
$.post(url, pars, function (response, type) {
if (type=='json') ...
if (type=='html') ...
});
There's no built-in way to do this, it's determined and tossed away by jQuery.httpData (note: it will be jquery.ajax.httpData in 1.4.3).
Though you can take a look at the httpData source and run the same functions yourself, that's a bit wasteful, since jQuery's doing it already. I
If your choices are only json or html, you could check typeof response, it should be "string" for HTML, otherwise you have JSON, which you could also check and be sure about as well, for example: type && type.propertyAlwaysThere.
If you have control of the server-side code as well, the easiest thing will probably be to include a parameter with a value to specify the format.
Here's an example where I did the same type of thing you're describing. I loaded a table with customer values from data returned in xml, json, or string format, all driven by the value my server-side code returned as the format parameter:
function checkCusts(id, format, resultRegion) {
var address = "cust-lookup.jsp";
var data = "cust_id_list=" + getValue(id) + "&format=" + format;
if (address != "") {
ajaxPost(address, data,
function(request) {
parseCustomers(request, format, resultRegion);
});
}
}
function parseCustomers(request, format, resultRegion) {
if ((request.readyState == 4) && (request.status == 200)) {
var headings = new Array("Customer ID", "First Name", "Last Name", "Balance");
var rows = null, customers = null;
if ("xml" == format) {
var xmlDocument = request.responseXML;
customers = xmlDocument.getElementsByTagName("customer");
rows = new Array(customers.length);
var subElementNames = ["cust_id", "first_name", "last_name", "balance"];
for (var i=0; i<customers.length; i++) {
rows[i] = getElementValues(customers[i], subElementNames);
}
} else if ("json" == format) {
var rawData = request.responseText;
var data = eval("(" + rawData + ")");
rows = data.customers;
} else if ("string" == format) {
var rawData = request.responseText;
var rowStrings = rawData.split(/[\n\r]+/);
rows = new Array(rowStrings.length -1);
for (var i=1; i<rowStrings.length; i++) {
rows[i-1] = rowStrings[i].split("#");
}
}
var table = getTable(headings, rows);
htmlInsert(resultRegion, table);
}
}
I've got a dropdown menu on my form, which when something is selected I need to reload the current page, but with an appended querystring.
How would I go about doing this?
This is an old question but it came up first in google search results.
The solution I went with is similar to jAndy's.
window.location.pathname gives me the page's url without the query string.
I'm then able to build the query string with "?"+$.param({'foo':'bar','base':'ball'}) which I then append to the pathname and set to window.location.href.
window.location.href = window.location.pathname+"?"+$.param({'foo':'bar','base':'ball'})
var params = [
"foo=bar",
"base=ball"
];
window.location.href =
"http://" +
window.location.host +
window.location.pathname +
'?' + params.join('&');
That code within your change event handler will do the trick.
For instance:
$('#my_dropdown_id').bind('change', function(){
var params = [
"foo=bar",
"base=" + $(this).val()
];
window.location.href = "http://" + window.location.host + window.location.pathname + '?' + params.join('&');
});
If you go with the top rated answer, you may want to replace
http://
in the code with
window.location.protocol
so that it works for other protocols, like https or file. So
window.location.href = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + params.join('&');
Actually, there a built-in function of location that you can use, the name of the function is assign.
For appending or modifying there is another built-in function of the URL class that you can use too. the name of the function is searchParams.
So for your case you just need below example:
const url = new URL(location.href);
url.searchParams.set('key', 'value');
location.assign(url.search);
Update 2022
I create a TypeScript function to apply redirect with params more easier:
const isClient = (): boolean => typeof window !== 'undefined';
type ParamsType = { [key: string]: string | number };
const redirectUrl = (url: string, params?: ParamsType): void => {
if (isClient()) {
try {
const _url = new URL(url);
if (params) {
const keyList = Object.keys(params);
for (let i = 0; i < keyList.length; i += 1) {
const key = keyList[i];
_url.searchParams.set(keyList[i], params[key]?.toString());
}
}
window.location.assign(_url.href);
} catch (e) {
throw new Error('The URL is not valid');
}
}
};
export default redirectUrl;
If you want a simple way to preserve the query string and possibly append to it, use window.location.search; here's a snippet:
var search = window.location.search + (window.location.search ? "&" : "?");
search += "param1=foo¶m2=bar";
window.location.href = window.location.protocol + "//" + window.location.host + window.location.pathname + search;
You can, of course, use a more sophisticated way of building the rest of your query string, as found in the other examples, but the key is to leverage Location.search.
If you have an existing querystring that you'd like to keep then this version does that and adds your new params to any existing ones. The keys are converted to lowercase so that duplicates are not added. Maintaining the quersytring does make the solution more complicated, so I'd only do this if you need to.
$("#sortby").change(function () {
var queryString = getQueryStrings();
// Add new params to the querystring dictionary
queryString["sortby"] = $("#sortby").val();
window.location.href =
window.location.protocol + "//" +
window.location.host +
window.location.pathname +
createQueryString(queryString);
});
// http://stackoverflow.com/questions/2907482
// Gets Querystring from window.location and converts all keys to lowercase
function getQueryStrings() {
var assoc = {};
var decode = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); };
var queryString = location.search.substring(1);
var keyValues = queryString.split('&');
for (var i in keyValues) {
var key = keyValues[i].split('=');
if (key.length > 1) {
assoc[decode(key[0]).toLowerCase()] = decode(key[1]);
}
}
return assoc;
}
function createQueryString(queryDict) {
var queryStringBits = [];
for (var key in queryDict) {
if (queryDict.hasOwnProperty(key)) {
queryStringBits.push(key + "=" + queryDict[key]);
}
}
return queryStringBits.length > 0
? "?" + queryStringBits.join("&")
: "";
}
I was having a requirement to open a particular tab after reloading. So I just needed to append the #tabs-4 to the current url. I know its irrelevant to current post but it could help others who come to this just like I did.
Using the code
window.location = window.location.pathname
+ window.location.search + '#tabs-4';
did'nt work for me but below code did.
location = "#tabs-4";
location.reload(true);