How do I attach detached objects - javascript

The title already says it ... I'm looking for a way to attach my detached objects.
http://jsfiddle.net/jy2Zj/
At the moment I can realize an alert only. How would I replace the function?
Thanks for your help.
Edit
Another question came up to my mind. Is there a way to suppress the closing of the select box after choosing "all"?

not sure if i understood what you meant..
If i am right you want to simply make a list of all detached objects so you can add them again later:
myArr = ['v2', 'v11'];
var detached = [];
$('select[name="test"] option').each(function() {
if ($.inArray(this.value, myArr) !== -1) {
detached.push($(this).detach());
}
});
$.each(detached,function() {
$('select[name="test"]').find('option').end().append(this);
});
$('select[name="test"]').find('option').end().append('<option value="all">All</option>');

Related

jQuery on.change specific element of array

I'm currently struggling with my specific problem. I'm using Symfony Collection entity type and https://symfony-collection.fuz.org/symfony3/ bundle for front-end render. When I click to add a new collection, the new set of input is rendered. I need to hide a specific inputs when a condition is not met. To do that I'm using jQuery. At the start I declare an array of possible HTML ids.
var regularityWeeksArray = [
'#user_working_hours_weeks_0_regularity', '#user_working_hours_weeks_1_regularity',
'#user_working_hours_weeks_2_regularity', '#user_working_hours_weeks_3_regularity'
]
Then I join it for jQuery's requirements, because I didnt figured out how to workaround that. I would love to use this code to run that, but I need to get which specific element of an array is being changed to give my function ID of the element. Now I'm changing the first one, because I don't know how to meet my requirements.
var regularityWeeksArrayToString = regularityWeeksArray.join(', ');
$(document).on('change', regularityWeeksArrayToString, function() {
if($(this).val() === 'interim'){
showInterimWithID(0);
} else {
hideInterimWithID(0);
}
});
Do you have any ideas how to do this? Thanks a lot in advance, I'm really losing my hair for couple of hours now.
//EDIT: for context, this is how showsInterimWithID() looks like, it shows specific inputs and its labels.
function showInterimWithID(id){
$('#user_working_hours_weeks_'+ id +'_interim_from, label[for=user_working_hours_weeks_'+ id +'_interim_from]').show();
$('#user_working_hours_weeks_'+ id +'_interim_to, label[for=user_working_hours_weeks_'+ id +'_interim_to]').show();
}
this.id is the ID of the target of the event. You can get its index in the array.
$(document).on('change', regularityWeeksArrayToString, function() {
var index = regularityWeeksArray.indexOf(this.id);
if($(this).val() === 'interim'){
showInterimWithID(index);
} else {
hideInterimWithID(index);
}
});

Utilizing .each() with an array

I am creating a Matching Card game using jQuery. Currently, I am running into an issue where the playerChoices array in my code does not update the 'matched' cards with the 'matched' class.
var playerChoices = [];
function showCard(){
$(this).addClass('selected'); //mark the selection with the selected class
playerChoices.push($(this)); //push the players choice onto the playerChoices array
console.log(playerChoices);
moves++;
console.log(moves);
$('#buttons').show();
matchCards(playerChoices);
}
Here is the function in question where the issues lie:
function matchCards(array){
if(playerChoices.length === 3){
//when the player finds the first match
if(playerChoices[0].attr('class') === playerChoices[1].attr('class')){ //if both playerChoices have the class
console.log("match found at index 0 and 1 of playerchoice!");
**$(playerChoices).each(playerChoices, function(index, element){
$(this).addClass('matched');**
})
}
//Deselect the two choices that were made
else{
$(playerChoices).each(function(index, element){
$(this).removeClass('selected');
})
playerChoices = [];
}
}
else if(playerChoices.length === 4){
//when the player gets the second match
if(playerChoices[2].attr('class') === playerChoices[3].attr('class')){
console.log("match found at index 2 and 3 of playerchoice!");
**$(playerChoices).each(playerChoices, function(index, element){
$(this).addClass('matched');**
})
**showGameOverMessage();**
}
//Deselect the last two choices that were made
else{
$(playerChoices).each(function(index, element){
$(this).removeClass('selected');
})
}
}
}
The primary issue here are the area's that I have 'asterisks' around in my code. I set up break points in the console, and I found that the code was never reaching the $(this).addClass('matched') lines. I've never used .each before and have looked at the examples api.jquery.com but I still was not able to overcome this issue of applying the matched class to my 'matched' cards.
FYI: I tried to get my code to work in JSFiddle but I kept getting errors with the images of my cards. My code works outside of that, I am just not able to get the matching class to apply appropriately.
https://jsfiddle.net/2sharkp/54s47vzb/ Works now
Any help is greatly appreciated!
Your updated question makes the problem clear: You're pushing jQuery instances into playerChoices:
playerChoices.push($(this));
...then later using $(playerChoices).each(...) to try to loop over them. While $() accepts arrays of HTML elements in the $() function, it doesn't correctly understand it if you pass it an array of jQuery instances — you end up with a jQuery instance wrapped around that set of jQuery instances, which isn't useful — you may as well just use the array (or use a single jQuery instance as I describe later).
You can use $.each (the one on the jQuery function itself):
$.each(playerChoices, function() {
// ...`this` (not `$(this)`) here will be a jQuery instance:
this.addClass('matched');
});
Updated Fiddle
But you really dont need $.each, just use the array's built-in forEach:
playerChoices.forEach(function(entry) {
// ...`entry` here will be a jQuery instance
entry.addClass('matched');
});
Updated Fiddle
...or there are lots of other ways to loop through arrays outlined in my answer here.
That said, you might consider making playerChoices a (single) jQuery instance. jQuery is set-based, so a single jQuery instance can contain multiple HTML elements that you can then act on with just a single method call. For instance, if you made playerChoices a jQuery instance, instead of:
playerChoices.forEach(function(entry) {
entry.addClass('matched');
});
You could do this:
playerChoices.addClass('matched');
To do that, start with:
playerChoices = $();
...and add elements via add:
playerChoices.add(this);
Try removing playerChoices before callback
$(playerChoices).each(function(index, element){
$(this).addClass('matched');
})
jsfiddle https://jsfiddle.net/xowkyh6p/1/

Use a Selector instead of "this" in Jquery

Maybe it's a silly question. But I really can't understand it.
I'm using the Jquery Cycle2. And after some personalization I got a simple problem.
I need to know what is the "Index" of my current slide.
On the plugin's website a found this line of code that perfectly works.
$('#cycle-1 .cycle-slide').click(function(){
var index = $('#cycle-1').data('cycle.API').getSlideIndex(this);
alert(index);
});
It gives me the right index. But I'm trying to catch this Index when another element is clicked. So I can't use the parameter (this).
Then I tried this.
$('.anotherelement').click(function(){
var mycycle = $('#cycle-1 .cycle-slide');
var index = $('#cycle-1').data('cycle.API').getSlideIndex($(mycycle));
alert(index);
});
It doesn't return my current slide index. It returns "-1". Does anyone knows how I should pass the Object (selector) as a parameter to the getSlideIndex() ?
Thanks a lot :D
You can use $('.cycle-slideshow').data('cycle.opts').currSlide to get the current slide index
$('.anotherelement').click(function(){
var index = $('.cycle-slideshow').data('cycle.opts').currSlide;
var currSliderNum = index+1;
alert(currSliderNum);
return false;
});
FIDDLE
In the first piece of code this is a DOM element and not a jquery object. Try this instead:
var index = $('#cycle-1').data('cycle.API').getSlideIndex(mycycle[0]);
However, presumably, you have multiple .cycle-slide elements. This will just get the first one. In your first code you have access to a single one since only one was clicked. You need to decide which one you want to target here.

Select tags that starts with "x-" in jQuery

How can I select nodes that begin with a "x-" tag name, here is an hierarchy DOM tree example:
<div>
<x-tab>
<div></div>
<div>
<x-map></x-map>
</div>
</x-tab>
</div>
<x-footer></x-footer>
jQuery does not allow me to query $('x-*'), is there any way that I could achieve this?
The below is just working fine. Though I am not sure about performance as I am using regex.
$('body *').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
Working fiddle
PS: In above sample, I am considering body tag as parent element.
UPDATE :
After checking Mohamed Meligy's post, It seems regex is faster than string manipulation in this condition. and It could become more faster (or same) if we use find. Something like this:
$('body').find('*').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
UPDATE 2:
If you want to search in document then you can do the below which is fastest:
$(Array.prototype.slice.call(document.all)).filter(function () {
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
There is no native way to do this, it has worst performance, so, just do it yourself.
Example:
var results = $("div").find("*").filter(function(){
return /^x\-/i.test(this.nodeName);
});
Full example:
http://jsfiddle.net/6b8YY/3/
Notes: (Updated, see comments)
If you are wondering why I use this way for checking tag name, see:
JavaScript: case-insensitive search
and see comments as well.
Also, if you are wondering about the find method instead of adding to selector, since selectors are matched from right not from left, it may be better to separate the selector. I could also do this:
$("*", $("div")). Preferably though instead of just div add an ID or something to it so that parent match is quick.
In the comments you'll find a proof that it's not faster. This applies to very simple documents though I believe, where the cost of creating a jQuery object is higher than the cost of searching all DOM elements. In realistic page sizes though this will not be the case.
Update:
I also really like Teifi's answer. You can do it in one place and then reuse it everywhere. For example, let me mix my way with his:
// In some shared libraries location:
$.extend($.expr[':'], {
x : function(e) {
return /^x\-/i.test(this.nodeName);
}
});
// Then you can use it like:
$(function(){
// One way
var results = $("div").find(":x");
// But even nicer, you can mix with other selectors
// Say you want to get <a> tags directly inside x-* tags inside <section>
var anchors = $("section :x > a");
// Another example to show the power, say using a class name with it:
var highlightedResults = $(":x.highlight");
// Note I made the CSS class right most to be matched first for speed
});
It's the same performance hit, but more convenient API.
It might not be efficient, but consider it as a last option if you do not get any answer.
Try adding a custom attribute to these tags. What i mean is when you add a tag for eg. <x-tag>, add a custom attribute with it and assign it the same value as the tag, so the html looks like <x-tag CustAttr="x-tag">.
Now to get tags starting with x-, you can use the following jQuery code:
$("[CustAttr^=x-]")
and you will get all the tags that start with x-
custom jquery selector
jQuery(function($) {
$.extend($.expr[':'], {
X : function(e) {
return /^x-/i.test(e.tagName);
}
});
});
than, use $(":X") or $("*:X") to select your nodes.
Although this does not answer the question directly it could provide a solution, by "defining" the tags in the selector you can get all of that type?
$('x-tab, x-map, x-footer')
Workaround: if you want this thing more than once, it might be a lot more efficient to add a class based on the tag - which you only do once at the beginning, and then you filter for the tag the trivial way.
What I mean is,
function addTagMarks() {
// call when the document is ready, or when you have new tags
var prefix = "tag--"; // choose a prefix that avoids collision
var newbies = $("*").not("[class^='"+prefix+"']"); // skip what's done already
newbies.each(function() {
var tagName = $(this).prop("tagName").toLowerCase();
$(this).addClass(prefix + tagName);
});
}
After this, you can do a $("[class^='tag--x-']") or the same thing with querySelectorAll and it will be reasonably fast.
See if this works!
function getXNodes() {
var regex = /x-/, i = 0, totalnodes = [];
while (i !== document.all.length) {
if (regex.test(document.all[i].nodeName)) {
totalnodes.push(document.all[i]);
}
i++;
}
return totalnodes;
}
Demo Fiddle
var i=0;
for(i=0; i< document.all.length; i++){
if(document.all[i].nodeName.toLowerCase().indexOf('x-') !== -1){
$(document.all[i].nodeName.toLowerCase()).addClass('test');
}
}
Try this
var test = $('[x-]');
if(test)
alert('eureka!');
Basically jQuery selector works like CSS selector.
Read jQuery selector API here.

How to get HTML data with javascript

I have an HTML web page full of divs and span tags identified with class that have lots of data I need in other format. I was wondering what would be the best way to do this with javascript.
Thank you for the help.
The fastest way? jQuery:
$(".myClass").each(function() {
// work with your data here
});
More lowlevel, but should be a lot faster (a lot less overhead):
var myelements = document.evaluate('//div[#class=myClass"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0; i < myelements.snapshotLength; i++) {
var dataElement = myelements.snapshotItem(i);
// work with your data here
}
(ok, you'd have to do it twice (once for div and once for span), it's more code and doesn't look as nice, but it should still be faster)
If you are wanting to get at all of the documents with a specific class then you will need to test for the presence of that class on each object. You will want to use a
document.getElementByTagName("*") // This should select everything
and loop through them to detect the proper name.
if (regex test == true) {
// you found an element that matches
// do what you will with it.
}
If you find the elements you need do what you need with them. Now you have processed all elements on the page and found elements that match your criteria. Good luck.

Categories