Rapid repeated traversing within a div - javascript

I have a number of divs, each of which contain an instance of a number of different items, each with their own unique classes and/or ids.
A lot of .js code applies to the elements within each of these parent divs, and my .js is getting bloated by the constant need to do things like:
// Stuff like this occurs 15-20 times for similar but different actions
$(this).parent().nextAll('.target').eq(0).find('.toggle').slideToggle();
$(this).next('.alert').html('Success');
In the context of the document, I see why this code is necessary. However, I feel that if I were only able to redefine the reference point as being the parent div instead of the whole document, I could replace the convoluted code above with the MUCH easier:
function keepingCodeWithinParentDiv(){
$('.toggle').slideToggle();
$('.alert').html('Success');
}
So, is there a way to say in Javascript: for this part nothing exists outside this div?

If you have a parent element (let's name it element) that you want to confine your jQuery selector operations to, you can just pass it as a context to any jQuery select:
$(".toggle", element).slideToggle();
See jQuery doc for more info.
If you show us your actual HTML and describe what you're trying to get, we could give more specific advice.

Related

CSS selector .find(">div.childCollapsible>div[data-onthemovecollapsible=true]") is not respecting parent restriction

Actual case is much more complicated but please play along. I am trying to select siblings of element that has class 'sss', by using
$('.sss').parent().parent().find(">div.childCollapsible>div[data-onthemovecollapsible=true]")
I can only use CSS selectors (this is part of Selenium thest). I expected to get only siblings of 'sss' however I am getting all the children of sub elements too.
How could I restrict it only to siblings?
or any other workaround that can get me from any element in the tree siblings only of any
data-onthemovecollapsible="true"
attribute holder.
EDIT: Firstly I would like apologise for failing to express myself clearly. The structure that I am working with is 'infinite tree structure' that has unknown amount of nodes on each layer, mechanism I am looking for is ability to get siblings on the same level that I am starting search from is and only children of his parent (his brothers + himself). All levels of tree have identical HTML syntax, so looking at them relatively from element one starts from, each layer is identical, hence the CSS selector should be identical too. I cannot use any other Jquery method but 'find', and only can use CSS selectors, as mechanism is part of selenium test so only By.CssSelector("...") can be used. I can traverse up the elements by using element.FindElements(By.XPath("..")) that gets me parent as I know how many levels up parent is, but from parent position I need to get all siblings without children (that have identical html syntax) in one go, so i would assume selector with only certain layer should do (like one in jsfiddle below), however it selects all the children nodes too - does not respect '>' for some reason. This would do nicely if I could use all JQuery functions.
$('.sss').parent().parent().children().children()
what I need is same result but with CSS selector.
http://jsfiddle.net/2a46U/
I think this will work for you:
.find("body>div>div>div>div.childCollapsible>div[data-onthemovecollapsible=true]")
If I'm understanding this correctly, you have two different restrictions here. One is that you only want siblings of an .sss element. The other is that the parent of the element is div.childCollapsible. I don't believe you will be able to do this with a single selector/find. You would need something like this:
// get the siblings of .sss with appropriate data attribute
var $els = $('.sss').siblings("div[data-onthemovecollapsible=true]");
// filter the collection to only those with appropriate parent
$els = $els.filter(function(){
return $(this).parent().is("div.childCollapsible");
});
http://jsfiddle.net/2a46U/4/
I've updated your jsfiddle with two options (check the console please):
Get all the siblings:
$('.sss').siblings();
Get specific siblings:
$('.sss').siblings("div.AppletBase")
If you need to set styles you can use the siblings selector in CSS3:
.sss ~ div.AppletBase {/* Your styles in here */}
Anything please leave a comment and I will review it again if is needed

JavaScript Id Handling

I'm developing a website that allows users to open multiple pages of the same content in the same browser window via inline 'windows'.
As the content can be repeated multiple times the id's can in turn be the same and therefore I have to "handle" them each so that I can distinguish between these pages.
I currently do this by assigning on load a unique id to the script like so:
var id_key;
function load_page() {
id_key++;
load_script("test.js") //load javascript file
}
//test.js:
$(function () {
var unique_id = id_key;
//adds the `unique id ` to the end of all elements with an id attribute set. ie `mycontainer` becomes `mycontainer_1`
update_ids(unique_id);
$("#mybtn_ " + unique_id).click(function () {
//do stuff
});
}
This works fine most of the time however if multiple pages are loaded too fast the Id tends to get overwritten causing confusion and errors.
I am wondering if there is a better technique of this doing this. I have heard of backbone.js but I am not sure whether that would be helpful in this case.
There are several general approaches to solve this kind of problem:
Load the sub pages in iframes. Each iframe gets it's own ID space. Scripts in all frames can talk to each other via the parent variable as long as all documents were loaded from the same domain.
Don't use any ids. Instead, give each "window" an ID and then locate elements in the window via classes and parent-child relations. Note that an element can have more than one class.
You can then use $(selector, win) to look for elements on a certain window win. The window becomes the "Selector Context" which means jQuery will search only children of the window and nothing else.
At the start of your script, locate all important elements by ID and save them in a JavaScript object. That way, you can access them without using a jQuery selector.
For example, you could select anything with an ID and save it with .data() in the window element. After this setup, all elements would be accessible via $(win).data('id')
You can generate quite good unique ids by concatenating a date and a random number:
new Date().getTime() + Math.random()
While this is by no means perfect, I think in your use case it will suffice.
As Jack mentioned in his comment, you can pass this id to your new window as a get parameter. I once did a whole OS-like interface with this method, and it worked flawlessly.

Multiple appendChild calls don't work

I read through several threads without find a clear answer.
I'm using a JavaScript library (Drinks.js) to put several widgets on my webpage.
The following code will add one single item to my div element pnlThermo:
function create(item) {
var thermo = Drinks.createElement('display');
thermo.setAttribute('id', item);
thermo.setAttribute('label', item);
Drinks.appendChild('pnlThermo', thermo);
}
Well, now I want to add several items to the same div element. No matter if I use a for cycle or call the function explicitly only the first item will be rendered. For example:
create('T1');
create('T2');
create('T3');
leads to show T1 only.
Perhaps I missed something, I'm quite new to JavaScript programming.
Thanks in advanced.
The reference manual ( http://goincompany.com/DTManual01.pdf ) says :
After you have created the HTML element, you have to append it to an
HTML container. In order to do this you have to use the appendChild
function, provided by the Drinks class. Drinks.appendChild('body',
gauge); 'body' is the id of the HTML container. If the parent is an
instrument, this function doesn't work. We have to use the appendChild
method of the instrument, but we'll see this later.
Seems to imply that the first parameter needs to be an HTML tagname, which makes little sense
but then the library is a little wierd IMHO.

Accessing Objects inside HTML Object with JS

I am creating an array of div tags inside the player table div. I'm getting all div tags with class .players. The divs with class name .players have input fieds and a link field inside. I want to be able to manipulate these (remove, add class, etc...)
What I thought would work would be something like:
$(divarray[j]+' .link').hide();
$(divarray[j]+' a').remove('.link');
But it's not working. Any thoughts? I'm sure it's something simple but it's my first time at JS :)
var divarray = $('#player-table > .players');
for( var j = 0; j < 10; j++){
$(divarray[j]).removeClass("players");
$(divarray[j]).addClass("selected_players");
$('#debug').append(divarray[j]);
$(divarray[j]+' a').hide();
}
First of all, you cannot just concatenate jQuery objects or DOM nodes with strings to create new selectors. jQuery provides methods for this kind of situations, where you already have an object or DOM node and want to find other related nodes.
Second, with jQuery there are much better ways to process a set of elements. Here is your code in more jQuery-like way. This is just an example, because I don't know the HTML structure. You have to adjust it so that it selects and applies to the correct elements.
$('#player-table > .players').slice(0,10) // gets the first 10 elements
.removeClass("players") // removes the class from all of them
.addClass("selected_players") // adds the class
.find('a').hide().end() // finds all descendant links and hides them
.appendTo('#debug'); // appends all elements to `#debug`
As you maybe see, there is only one semicolon at the last line. That means this whole code block is just one statement, but splitting it up over several lines increases readability.
It works because of the fluent interface, a concept which jQuery heavily makes use of. It lets you avoid creating jQuery objects over and over again, like you do ($(divarray[j])).
Another advantage is that you can work on the whole set of elements at once and don't have to iterate over every element explicitly like you have to do with "normal" DOM manipulation methods.
For learning JavaScript, I recommend the MDN JavaScript Guide.
jQuery has a couple of tutorials and a very good API documentation.
Read them thoroughly to understand the basics. You cannot expect to be able to use a tool without reading its instructions first.
Try this istructions
$(divarray[j]).find('.link').hide();
$(divarray[j]).find('a').remove('.link');
Try also
$(divarray[j]).find('.link:first').hide();
If you need to work only on the first element
Hope it helps

Complex jquery selection that also involves custom xml tags

I want to write a select something like...
#window_4 > content > p:eq(0)
I think I have this correct, but I have a few selectors that are all similar but I can't test them all at once.
Am I right in saying this is selecting an element, who is the fist p tag child of a content tag that is a child of a tag with id 'window_4'
If I have gotten this wrong, can you give me some pointers. Would love to be able to simplify this code, I have more code selecting the tag I am after then actually doing stuff with them.
Looks good to me, although you can make it a bit more readable by substituting p:eq(0) for p:first.
Edit for comment:
jQuery always returns an array of elements, no matter whether 0, 1 or many elements were found. On these elements, yes, you can perform JS functions, such as innerHTML. You can access each element returned by jQuery just as if you would any other array:
$(".red")[0].innerHTML = "Glen Crawford";
More info: http://groups.google.com/group/jquery-ui/browse_thread/thread/34551a757f139ae1/20111f82c2596426

Categories

Resources