Get URL array variables in javascript/jquery - javascript

I've got a bunch of parameters being passed to a page by URL variables. The URL looks sort of like:
file.aspx?category[]=1&category[]=7&category[]=3&id=8az
Using the jQuery getUrlParam extension I can get url variables very easily, but rather than returning category as an array (which is what I want) it gets returned as null.
Is there a way for me to read these into a javascript array?

I previously pointed to this question: Get QueryString values with jQuery - but as #Crescent Fresh pointed out, those examples don't deal with arrays in the query string (and besides, they're a bit slow I think.
So I cooked up my version of this function:
function getQueryString () {
var ret = {};
var parts = (document.location.toString().split('?')[1]).split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i].split('=');
// so strings will be correctly parsed:
p[1] = decodeURIComponent(p[1].replace(/\+/g, " "));
if (p[0].search(/\[\]/) >= 0) { // then it's an array
p[0] = p[0].replace('[]','');
if (typeof ret[p[0]] != 'object') ret[p[0]] = [];
ret[p[0]].push(p[1]);
} else {
ret[p[0]] = p[1];
}
}
return ret;
}
But there are caveats. It will only work on a correctly formed query string - there's no error detection. Also, it does not work on numbered/indexed arrays.. that is when your array is defined in the query string as:
?category[3]=1&category[4]=7&category[20]=3&id=8az
It would be trivial to add to the .search() query a regex for finding that as well, but I'm not the best regex expert... anybody got ideas?

Shouldn't it be: file.aspx?category=1&category=7&category=3

Related

Javascript efficient search array for value with jQuery

There's a gap in my JavaScript knowledge here. I want to search an array of objects values for a particular value and return it.
For the year I have been writing JavaScript, I have been implementing it like this:
var itemClicked = (function(){
var retval;
//Note self.inventory.itemsArray is an array of JS objects
$(self.inventory.itemsArray).each(function(i){
if(parseInt(this.id) === parseInt(idOfItem)){
retval = this;
return false;
}
});
return retval;
})();
It works, but I'm sure as anything there is a more elegant way. Tell me please!
EDIT - Solution
Thanks to #gdoron with his answer below.
var myVar = $(self.owner.itemsArray).filter(function(){
return parseInt(this.id) == parseInt(recItemID);
}).get(0);
Note: .get(0) was added at the end because myVar is wrapped as a jQuery object.
The native jQuery function for this is filter:
$(data).filter(function(){
return this.id == "foo";
});
It's shorter than code you have and more important a lot more readable.
About efficiency, it will iterate all the elements in the set to find as much as possible matches, but I hardly believe it will be the bottle neck of your application, don't focus on micro-optimisations.
I suggest you read Eric Lipper blog about Which is faster.
You can also use grep as suggested by #Mattias Buelens:
$.grep(data, function(ele){
retun ele.id == "foo";
});
Just another option using jQuery's $.grep( ) function
var arr = $.grep( self.inventory.itemsArray, function ( n ) {
return n.id == idOfItem;
});
The above returns an array of matching array elements. If you just want the first it is easy enough to return arr[0] if it exists.
Although I'm unsure what the function is actually supposed to do (due to the external contexts' variables), the following should be more efficient cycle-wise
var itemClicked = (function(){
var i, array = self.inventory.itemsArray, length = array.length;
for( i=0; i < length; i++) {
if(parseInt(array[i].id) === parseInt(idOfItem)){
return array[i];
}
}
return undefined;
})();
It's an array of Javascript objects
Then do not use jQuery at all. At least, use $.each instead of building a wrapper object around the array. Still, a simple for-loop is much shorter and more performant:
var itemClicked = (function(idnum) {
var arr = self.inventory.itemsArray;
for (var i=0, l=arr.length; i<l; i++)
if (parseInt(arr[i].id, 10) === idnum)
return arr[i];
})( parseInt(idOfItem, 10) );
You might as well think of storing the id properties as numbers right away, so you don't need to convert it each time.

Custom for-loop helper for EmberJS/HandlebarsJS

A small two hours ago I started: Nested HandlebarsJS #each helpers with EmberJS not working
Shortly after I figured an acceptable temporary solution myself, question is still unaswered. My problems didn't stop there though.
I am now trying to make a custom helper which will loop through an array of objects, but exclude the first index - pretty much: for(i = 1; i < length; i++) {}. I've read on websites you have to get the length of your context and pass it to options - considering your function looks like: forLoop(context, options).
However, context is a string rather than an actual object. When you do a .length, you will get the length of the string, rather than the size of the array. When I pass that to options, nothing happens - not too mention browser freezes.
I then first tried to do a getPath before passing it to options, this returns an empty string.
What am I supposed to do instead, I made the for-loop code before for just HandlebarsJS and that worked, but EmberJS doesn't seem to take it, why?
EDIT: I pretty much also followed: http://handlebarsjs.com/block_helpers.html -> Simple Iterators
I solved this myself after trying for a long time.
The HandlebarsJS method (as described on the site) is no longer valid for EmberJS, it's now as follows:
function forLoop(context, options) {
var object = Ember.getPath(options.contexts[0], context);
var startIndex = options.hash.start || 0;
for(i = startIndex; i < object.length; i++) {
options(object[i]);
}
}
Heck, you could even extend the for-loop to include an index-value!
function forLoop(context, options) {
var object = Ember.getPath(options.contexts[0], context);
var startIndex = options.hash.start || 0;
for(i = startIndex; i < object.length; i++) {
object[i].index = i;
options(object[i]);
}
}
This is a working for-loop with variable start index. You use it in your templates like so:
{{#for anArray start=1}}
<p>Item #{{unbound index}}</p>
{{/for}}
Here is how I did it (and it works !!!)
First,
i had in my model a 'preview' property/function, that just return the arrayController in an array :
objectToLoop = Ember.Object.extend({
...
arrayController: [],
preview: function() {
return this.get('arrayController').toArray();
}.property('arrayController.#each'),
...
});
Then, I add a new Handlebars helper :
Handlebars.registerHelper("for", function forLoop(arrayToLoop, options) {
var data = Ember.Handlebars.get(this, arrayToLoop, options.fn);
if (data.length == 0) {
return 'Chargement...';
}
filtered = data.slice(options.hash.start || 0, options.hash.end || data.length);
var ret = "";
for(var i=0; i< filtered.length; i++) {
ret = ret + options.fn(filtered[i]);
}
return ret;
});
And thanks to all this magic, I can then call it in my view :
<script type="text/x-handlebars">
<ul>
{{#bind objectToLoop.preview}}
{{#for this end=4}}
<li>{{{someProperty}}}</li>
{{/for}}
{{/bind}}
</ul>
</script>
And that's it.
I know it is not optimal, so whoever have an idea on how to improve it, PLEASE, make me know :)

How can I parse the first JSON object on a stream in JS

I have a stream of JSON objects, as with JSON-RPC over TCP or WebSockets. There's no length prefix or delimiter, because JSON is self-delimiting. So, when I read from the stream, I may end up with something like this:
{"id":1,"result":{"answer":23},"error":null}
{"id":2,"result":{"answer":42},"error":null}
{"id":3,"result":{"answ
I need to parse each JSON object one by one. I can't do this with JSON.parse, because it will just throw a syntax error for extraneous data at the end.
Of course with that example I could go line by line, but I can't rely on the whitespace looking like that; JSON-RPC can just as easily look like this:
{
"id": 1,
"result": {
"answer": 23
},
"error":null
}
Or this:
{"id":1,"result":{"answer":23},"error":null}{"id":2,"result":{"answer":42},"error":null}
With most parsers in other languages, the obvious answer is something like this (using Python as an example):
buf = ''
decoder = json.JSONDecoder()
def onReadReady(sock):
buf += sock.read()
obj, index = decoder.raw_decode(buf)
buf = buf[index:]
if obj:
dispatch(obj)
But I can't find anything similar in JS. I've looked at every JS parser I can find, and they're all effectively equivalent to JSON.parse.
I tried looking at various JSON-RPC frameworks to see how they handle this problem, and they just don't. Many of them assume that a recv will always return exactly one send (which works fine for JSON-RPC over HTTP, but not over TCP or WebSockets—although it may appear to work in local tests, of course). Others don't actually handle JSON-RPC because they add requirements on whitespace (some of which aren't even valid for JSON-RPC).
I could write a delimiter check that balances brackets and quotes (handling escaping and quoting, of course), or just write a JSON parser from scratch (or port one from another language, or modify http://code.google.com/p/json-sans-eval/), but I can't believe no one has done this before.
EDIT: I've made two versions myself, http://pastebin.com/fqjKYiLw based on json-sans-eval, and http://pastebin.com/8H4QT82b based on Crockford's reference recursive descent parser json_parse.js. I would still prefer to use something that's been tested and used by other people rather than coding it myself, so I'm leaving this question open.
After a month of searching for alternatives and not finding anything useful, I decided to code up a bunch of different implementations and test them out, and I went with my modification of Crockford's reference recursive-descent parser (as described in the question, available here).
It wasn't the fastest, but it was more than fast enough in every test I did. More importantly, it catches clearly erroneous JSON, when that's not ambiguous with incomplete JSON, much better than most of the other alternatives. Most importantly, it required very few, and pretty simple, changes from a well-known and -tested codebase, which makes me more confident in its correctness.
Still, if anyone knows of a better library than mine (and just being used by lots of projects instead of just me would count as a major qualification), I'd love to know about it.
Here is a simple JSON Object separator. It assumes that you receive a series of JSON objects (not array) and that are well formed.
function JSONObjectSepaator() {
this.onObject = function (JSONStr) {};
this.reset = function () {
this.brace_count = 0;
this.inString = false;
this.escaped = false;
this.buffer = "";
};
this.receive = function (S) {
var i;
var pos=0;
for (i = 0; i < S.length; i++) {
var c = S[i];
if (this.inString) {
if (this.escaped) {
this.escaped = false;
} else {
if (c == "\\") {
this.escaped = true;
} else if (c == "\"") {
this.inString = false;
}
}
} else {
if (c == "{") {
this.brace_count++;
} else if (c == "}") {
this.brace_count--;
if (this.brace_count === 0) {
this.buffer += S.substring(pos,i+1);
this.onObject(this.buffer);
this.buffer = "";
pos=i+1;
}
} else if (c == "\"") {
this.inString = true;
}
}
}
this.buffer += S.substring(pos);
};
this.reset();
return this;
}
To use it, you can do it this way:
var separator = new JSONObjectSepaator();
separator.onObject = function (o) {
alert("Object received: "+o);
};
separator.receive('{"id":1,"result":{"answer":23},"error":null, "x');
separator.receive('x":"\\\""}{"id":2,"result":{"answer":42},"error":null}{"id":');
separator.receive('3,"result":{"answer":43},"err{or":3}');
Pragmatic answer: use python
pos = 0
try:
while not pos == len(str(body)):
# raw_decode will parse as much of the line as possible and return how much was left
j, json_len = decoder.raw_decode(str(body)[pos:])
pos += json_len
# "j" holds your object
I'm writing some code to parse large numbers of JSON files saved from streams which have from 1 to 50 JSON objects in each one. This is a JavaScript hack but it works for my purposes (relies on the error message containing the position of the "bad" JSON. If the error character is a "{" then I know it's probably the start of a new object):
let contents = ""; // your JSON string
let startIndex = 0;
let endIndex = contents.length;
do {
let obj;
try {
let str = contents.slice(startIndex, endIndex);
obj = JSON.parse(str);
startIndex = endIndex;
endIndex = contents.length;
console.log("successfully parsed", obj);
}
catch (e) {
let match = e.toString().match(/^SyntaxError: Unexpected token { in JSON at position (\d+)$/);
if (match && match.length == 2) {
endIndex = parseInt(match[1]) + startIndex;
}
else throw e;
}
} while (startIndex < endIndex);

Use Javascript or jQuery to create an array from an array

Assume you have an array:
var arrStateCityAll=['CA_Alameda','CA__Pasadena','CA_Sacramento','NY_Albany','NY_Buffalo','NY_Ithaca']
Is there an easy way using javascript and/or jQuery to filter the arrStateCityAll to get a new array (a subset of arrStateCityAll); something like this:
// return's ['CA_Alameda','CA__Pasadena','CA_Sacramento']
var arrStateCityCA=FilterArray('CA',arrStateCityAll);
Likely you want to do a regex on each item. You can do this with jQuery's grep function.
http://api.jquery.com/jQuery.grep/
You can use javascript's Array.filter.
var arrStateCityAll = ['CA_Alameda','CA__Pasadena','CA_Sacramento','NY_Albany','NY_Buffalo','NY_Ithaca']
var arrStateCityCA = arrStateCityAll.filter( function (element) {
return element.indexOf("CA_") == 0;
});
The mozilla documentation linked to above has a solution for browsers that don't implicitly support filter.
This should work.
var arrStateCityCA = [];
for (var i = 0;i<arrStateCityAll.length;i++){
if (arrStateCityAll[i].substr(0,2) == 'CA'){
arrStateCityCA.push(arrStateCityAll[i]);
}
}
You could use jQuery.grep
var arrStateCityCA =
$.grep(arrStateCityAll,function(el,i){return (el.substring(0,2)=='CA')});
Demo at jsfiddle
To implement you actual FilterArray function as shown in your post you could do
function FilterArray(state,arr){
return $.grep(arr,
function(el,i) {return (el.substring(0,2)==state)}
);
}
This makes a few assumptions.
State is always 2 chars.
State is always the first 2 chars.
And of course remember case-sensitivity (this function is case sensitive) ie 'CA' not equal to 'Ca'.
if you are going to have an undescore between your state and city name, you can split on the underscore and test against the first array value
function getSubSetByState(set,state) {
var result = [];
for(var i=0,l=set.length;i<l;++i) {
if(set[i].split('_')[0] === state) {
result.push(set[i]);
}
}
return result;
}
Use if by giving it the set of places, and then the state you are searching for.

How do I avoid looping through an array to find a partial match?

I am looping through an array of english phrases, and if i find a match, with the current text node, i replace it with it's translation in the non_english array. All of that works 100% for exact matches.
But for partial matches, I need to use the .match command, which allows for partial matches.
My code to search for exact matches is like this:
var found = $.inArray(value,en_lang);
Then if there is a found value, then do replacement of text. This method is fast and I love it.
However to do partial word/phrase matching, I have to use this looping code.
// loop thru language arrays
for (var x = en_count; x > 0; x--) {
// assign current from/to variables for replace
var from = en_lang[x];
var to = other_lang[x];
// if value match do translation
if (value.match(from)) {
content(node, value.replace(from, to));
}
// mark this node as translated
if ($.browser.msie == 'false') {
$(node).data('translated', 'yes');
}
}
This does the job but is pretty slow. After a lot of research, I have found that I can convert the english array to a list-based string via the join command.
But I am unable to come up with a function to search this list for a partial match, and return the position in the list.
I was trying out this old js function created in 2006. But I can't figure out how to get the position back, correctly.
function listfind(list, value, delimiters) {
if (!delimiters) {
var delimiters = ','
}
_TempListSplitArray = list.split(delimiters)
var FoundIdx = 0;
for (i = 0; i < _TempListSplitArray.length; i++) {
if (_TempListSplitArray[i] == value) {
FoundIdx = i + 1;
break
}
if (value.match(_TempListSplitArray[i])) {
FoundIdx = i + 1;
break
}
}
return FoundIdx
}
Thank you for your time.
Javascript has a foreach type of system but its still based on a loop
var array = ['hello', 'world'];
for(var key in array){
alert(array[key]);
}
Thats the best your getting for looping though an array but this way allso works with objects
var obj = {'one':'hello', 'two':'world'];
for(var key in obj){
alert("key: "+key+" value: "+obj[key]);
}
UPDATED for Comments on your question
You can just replace the text you know
var str = "hello World";
str = str.replace("hello", "Bye bye");
alert(str);

Categories

Resources