Rewriting .each() loop as for loop to optimize, how to replicate $(this).attr() - for-loop

I running into some performance issues with a jquery script I wrote when running in IE so I'm going through it trying to optimize any way possible. Apparently using for loops is way faster than using the jQuery .each method. This has led me to a question regarding the equivalent of $(this) inside a for loop. I'm simplifying what I'm doing in my loop down to just using an attr() function as it gets across my main underlying question.
Im doing this with each(simplified)
var existing = $('#existing').find('div');
existing.each(function(){
console.log($(this).attr('id'));
});
And I've tried rewriting it as a for loop as such:
var existing = $('#existing').find('div');
for(var i = 0;i < existing.length;i++)
{
console.log(existing[i].attr('id'));
}
Its throwing an error saying:
Uncaught TypeError: Object #<HTMLDivElement> has no method 'attr'

You need existing.eq() to get jQuery object, existing[] gives you DOM object. The function attr() should be called with jQuery object but not with DOM (javascript) object.
var existing = $('#existing');
for(var i = 0;i < existing.length;i++)
{
console.log(existing.eq(i).attr('id'));
}
You can use each to get index without for loop.
existing.each(function(index, item){
alert(index);
alert(item);
});

To get the id of an element just do
existing[i].id
Note that you jQuery loop would also be faster as
existing.each(function(){
console.log(this.id);
});
More generally, you should not use attr('id'), especially if you're concerned by performances, as a DOM object has a property id.

.I have to ask you a question before I give my answer, why would you need to perform a loop on a single element, #existing is an Id not, therefore it's a unique element on your page.
you could simply do
$('#existing').prop('id');
In case your have more than one elements, you should be using a class or another attribute, if that is the case, you could use the following:
$.each('.existing',function(index,item){
console.log(item.prop('id'));
});
better use prop() insted of attr() as attr is deprecated

Related

How to access variables of 1 function in another function defined within the same function in javascript

This is my JavaScript code.
function postFile(){
var obj=new Object();
obj.category=document.getElementsByName("gtitle")[0].value;
obj=obj.stringify(obj);
sendDetails("http://localhost:8080/Megabizz/webapi/gallery", obj);
var r;
ajaxRequest.onreadystatechange = function(){
if(ajaxRequest.readyState == 4){
r=new Object(JSON.parse(ajaxRequest.responseText));
console.log(r.status);
}
};
//r not accessible here
}
In the function postFile(), I have a declared a variable r now I am manipulating this r using ajaxRequest object.
Now when I am trying to access this r outside the function onreadystatechange(),
I am getting an error that "r is undefined".
I think that the function onreadystatechange() is declaring a new variable r instead of manipulating r declared above the onreadystatechange() function.
Tell me the way to overcome this problem.
//Another problem
var x;
function x(){
x=document.getElementByID("upload-buton");
}
function y(){
x.value='some text';
}
In this case, the value of x which I am setting in function y() does not remain same for the function x().
I am getting an error "cannot set property value for undefined".
Please figure out the cause behind this error.
Ajax (Asynchronous JavaScript and XML) makes your code Asynchronous. That means that not everything in your code happens in a straightforward manner (the code might not be executed in the order it is written).
For basic understanding async code see a tutorial Event-Based Programming: What Async Has Over Sync.
ajaxRequest.onreadystatechanges fires on state change event. After that, you are comparing ajaxRequest.readyState, which means that however r variable is always accessible, it will be changed only on 4: request finished and response is ready and will only be available after the completion of the Ajax request. Javascript will not wait for the Ajax request to finish.
A solution strongly depends on further actions you wish to do with r variable.

ionic - there is a way to delete the cache in controller method?

I know how to make the cache cleared for view :
.state('app.list', {
cache : false,
url: "/lists/:listId",
views: {
'menuContent': {
templateUrl: "templates/listDashboard.html",
controller: 'listDashboardCtrl'
}
}
})
, but I need something else - delete all the cache for the app in controller method. how to do it?
I found a solution, Wrap the clearCache and ClearHistory in a $timeout. Something Like this.
$scope.logout = function(){
$location.path('/signin')
$timeout(function () {
$ionicHistory.clearCache();
$ionicHistory.clearHistory();
$log.debug('clearing cache')
},300)
}
Edit:Changed Timeout seconds
You can use $ionicHistory. From documentation:
clearCache()
Removes all cached views within every ionNavView. This both removes the view element from the DOM, and destroy it's scope.
In your listDashboardCtrl write this:
function listDashboardCtrl($scope, $ionicHistory){
$ionicHistory.clearCache();
}
Well this is an old issue, but for anyone that's coming 2017 or later I will explain what really happens and how to solve it:
The code of $ionicHistory.clearCache():
clearCache: function(stateIds) { return $timeout(function() {
$ionicNavViewDelegate._instances.forEach(function(instance) {
instance.clearCache(stateIds); }); }); }
So, as you can see, it takes 1 parameter cllaed stateIds which is an array of stateId. Indeed i struggled to find out that stateId is nothing more than stateName.
So, let's go deeper. The code of $ionicNavView.clearCache which is used in the line above "instance.clearCache(stateIds)" is:
self.clearCache = function(stateIds) {
var viewElements = $element.children();
var viewElement, viewScope, x, l, y, eleIdentifier;
for (x = 0, l = viewElements.length; x < l; x++) {
viewElement = viewElements.eq(x);
if (stateIds) {
eleIdentifier = viewElement.data(DATA_ELE_IDENTIFIER);
for (y = 0; y < stateIds.length; y++) {
if (eleIdentifier === stateIds[y]) {
$ionicViewSwitcher.destroyViewEle(viewElement);
}
}
continue;
}
if (navViewAttr(viewElement) == VIEW_STATUS_CACHED) {
$ionicViewSwitcher.destroyViewEle(viewElement);
} else if (navViewAttr(viewElement) == VIEW_STATUS_ACTIVE) {
viewScope = viewElement.scope();
viewScope && viewScope.$broadcast('$ionicView.clearCache');
}
}
};
And as you can see in the code, this clearCache DOES NOT CLEAR ALL CACHES, instead, it destroy all cached views that matches a value in the stateIds array. If there's no parameter IT JUST DESTROY THE ACTUAL VIEW.
So the solution for this, using just the Ionic way is to call $ionicHistory.clearCache() with all your state names in an array as parameter.
E.g:
$ionicHistory.clearCache(['login', 'map', 'home']);
I cannot belive any Ionic developer didnt dug into the code before, or missed this simple datail.
I Hope someone takes advantage of this, even being so late.
UPDATE: Just to make it crystal clear, i want to point out where the bug itself is (if we can call it bug), maybe can be handy for devs:
self.clearCache = function(stateIds){
[...]
var viewElements = $element.children();
}
What the whole function does is basically:
Get all elements using JQLite
Loop the elements
Check if an element equals one in the StateIds array and destroy it; go to next element.
Check if element in the loop is cached or active, and in both true cases destroy it
I wont dig deeper into this but debugging it i could see that the elements gotten from var viewElements = $element.children(); is not an array of all your views content, not even the cached ones, intentionally or not it does not loop through out all your states to clear all those that matches 'ACTIVE' or 'CACHED'. If you want it to loop through ALL your states and destroy all cached views and data you need to explicity pass the stateIds array parameter.
Besides there's another strange behavior, because when i was debugging it i saw when the var viewElements array was filled up with 2 elements, and these 2 elements were from the same state, one resolved to 'CACHED' another resolver to 'ACTIVE', even resolving to the 2 types used in the if conditions the cache was not cleared at all.
I personally think that this is somekind wrong implemented or is wide used wrongly. The fact is that there's a lot of people cracking their heads on this and devs don't even give this simple explanation.

make document.getElementById into a var

Is there any way you can make "document.getElementById" into a variable?
I want to be able to write
myVariable("id").innerHTML = (blabla);
instead of
document.getElementById("id").innerHTML = (blabla);
Pardon me if this has been answered. I've sought and found nil! newbie
You can wrap the output into another function
var shortID = function(id) {
return document.getElementById(id);
}
shortID('myID').innerHTML = "...";
To provide a simpler way to call common code, you can just define your own function like migvill suggests.
To answer the question directly though, you can point to the document.getElementById function (or any other function) using a variable. This is as obvious as you could imagine:
var myVariable = document.getElementById;
The problem with this is that the function itself (the object that myVariable now points to) is not intrinsically linked to the document object that it is designed to work with. When you write document.getElementById("id"), the document is automatically given to the function, but with myVariable you would need to specify it. This can be done using the call function:
myVariable.call(document, "id").innerHTML = "blabla";
And finally, the bind function can be used to create a new function that automatically links the given object (this has essentially the same effect as defining your own wrapper function):
var newFunc = myVariable.bind(document);
newFunc("id").innerHTML = "blabla";

Order $each by name

I am trying to figure why my ajax $each alters the way my list of names gets printed?
I have an json string like this:
[{"name":"Adam","len":1,"cid":2},{"name":"Bo","len":1,"cid":1},{"name":"Bob","len":1,"cid":3},{"name":"Chris","len":1,"cid":7},{"name":"James","len":1,"cid":5},{"name":"Michael","len":1,"cid":6},{"name":"Nick","len":1,"cid":4},{"name":"OJ","len":1,"cid":8}]
Here all the names are sorted in alphabetic order, but when getting them out they are sorted by "cid"? Why, and how can I change this?
Here is my jQuery:
var names = {};
$.getJSON('http://mypage.com/json/names.php', function(data){
$.each(data.courses, function (k, vali) {
names[vali.cid] = vali.name;
});
});
I guess its because "names[vali.cid]", but I need that part to stay that way. Can it still be done?
Hoping for help and thanks in advance :-.)
Ordering inside an object is not really defined or predictable when you iterate over it. I would suggest sorting the array based on an internal property:
var names = [];
$.getJSON('http://mypage.com/json/names.php', function(data){
$.each(data.courses, function (k, vali) {
names.push({name: vali.name, cid: vali.cid});
});
names.sort(function(a, b) {
return a.name.localeCompare(b.name);
});
});
Now you have an array that is ordered and you can iterate over it in a predictable order as well.
There is no "ajax $each" - you probably mean the jQuery function.
With "when getting them out" I presume you mean something like console.debug(names) after your $each call
Objects aren't ordered in javascript per definition, so there is no more order in your variable "names". Still, most javascript implementations today (and all the ones probably important to you - the ones used in the most used browsers) employ a stable order in objects which normally depends on the order you insert stuff.
All this said, there can probably be 3 reasons you're not getting what you're expecting:
Try console.debug(data) and see what you get - the order as you want it?
As you don't explicitly state how you debug your stuff, the problem could be in the way you output and not the data is stored. Here too try console.debug(names).
You're using a function which dereferences on expection, like console.*. This means if you console.debug() an object, the displayed values will depend on the moment you unfold the displayed tree in your browser, not when the line was called!

Prototype Selector : simple examples

i'm just starting prototype, i was on jquery before.
I can't find easy examples on the internet about how :
Selecting all elements having the same id on a page
(I'm doing this but it only works for the first element : $('mydiv').hide() )
Selecting a div that is contained in another div by their id.
hiding all elements that have myClass class.
As mentioned above you shouldn't have the same ID on a page more then once. Besides being against standards it's a recipe for potential problems since you don't know how your JavaScript will react to it. Uses classes instead.
Selecting all elements having the same
id class on a page (i'm doing this but it
only works for the first element :
$('mydiv').hide() )
Use $$:
$$('.myclass')
Selecting a div that is contained in
another div by their id.
Use $$:
$$('div#outer div#inner')
hiding all elements that have myClass
class.
Use $$, each(), and hide()
$$('.myClass').each(function(d) {
d.hide();
});
$$ is your friend.
A few things i would add.
$$('.myClass').each(function(d) {
d.hide();
});
can be replaced with this:
$$('.myClass').invoke("hide");
Also, be careful with your use of $$, within a page with a large dom it is usually faster to target a parent element with $ and then use select() for your selector
so
$$('div#outer div#inner') etc....
can be rewritten like this:
$('parent_of_inner_and_outer').select('div#outer div#inner') etc....
This isn't particularly pretty, but if you run into a situation like I did recently, where there could potentially be multiple items with the same id on the page and you don't have the ability to change that, then something like this will work. In my case, I at least knew they were all in span tags.
var spans = $$('span');
for (i = 0; i < spans.length; i++) {
var span = spans[i];
if (span.id == 'add_bookmark_image_' + id) {
span.hide();
}
if (span.id == 'is_bookmarked_image_' + id) {
span.show();
}
}

Resources