Attach event to a dynamically created dom element - javascript

In the code below I'm dynamically creating different posts.
Each post has its own image.
$(function () {
for(post in data){
//get from the data post details
var titleData = data[post]["title"];
var descriptionData = data[post]["description"];
var imageData = "images/"+data[post]["image"];
//create elements with jquery
var postHolder = $('<div class="post row"></div>');
var img = $('<img src="'+imageData+'" data-title="'+titleData+'" class="col-sm-3 img-post">');
var textHolder = $('<div class="col-sm-9"></div>');
var title = $('<h4 class="title-post"></h4>').append(titleData);
var description = $('<p class="explanation-post"></p>').append(descriptionData);
textHolder.append(title);
textHolder.append(description);
postHolder.append(img);
postHolder.append(textHolder);
$('.posts-container').append(postHolder);
img.on('click',function(){alert(this.data-title);});
}
});
I want that when I click the image, it will alert the title of the post (what's known as "titleData") and that the "textHolder" will change his background color to grey.
The limitation on this challenge are:
To pass a different parameter as the "titleData" each time.
To use minimum space in the memory.

data-title is invalid identifier in JavaScript. To access the data-* attributes, You can use HTMLElement.dataset
alert(this.dataset.title)
OR, As you are using jQuery .data() method.
alert($(this).data("title"));

What is in the alert is wrong.
You are saying
this.data MINUS title
You sould be using bracket notation if the name has a dash in it.
alert(this["data-title"]);
or better with getAttribute
alert(this.getAttribute("data-title"));
or jQuery
alert($(this).data("title"));
alert($(this).attr("data-title"));
so the final code with the bg color change should be
img.on('click', function() {
alert($(this).attr("data-title"));
textHolder.css("background-color","#CCC");
console.log(textHolder.css("background-color"))
});

Related

Jquery select object by id dynamically using a string

I have an image gallery that uses modals. In the image modal or outside it, the user can click on a star and mark the image as favorite. Favorite images have a class that makes the star change color its to 'golden'. If a user marks a favorite in the modal, I need to change the color of the star of that image outside the modal as well.
To do this, I thought I could have a
<p id = "modal_counter" class = "hidden">number</p>
in the modal, so that I can get the image number. Then I use that image number as part of a jquery selector.
The images in the gallery have something like this:
<p id = "image_number" class = "hidden"></p>
<!-- for example: <p id = "image_2" class = "hidden"></p> -->
So, all I need is to successfully select the hidden p tag next to each image, then I could use jquery's next() or parent().find().
This is the relevant code:
...
var modal_counter = div_parent.find('#modal_counter').text();
var counter = "#image_"+String(modal_counter);
/* I would like the counter to be something like "#image_2" */
var $(counter).parent().find('.star').addClass('golden')
...
This doesn't work. Jquery tries to find an object using this selector:
"#image_\n 2"
and of course, it doesn't find one. I tried removing the \n with a regex, but it still doesn't work:
counter_processed = modal_counter.replace(/(<([^>]+)>)/ig,"");
It'll probably be better to use a data-attribute on your element rather than getting the text content. Do:
<p id = "modal_counter" class = "hidden" data-counter="number">number</p>
Then you can:
...
var modal_counter = div_parent.find('#modal_counter').data('counter');
var counter = "#image_" + modal_counter;
/* I would like the counter to be something like "#image_2" */
var $(counter).parent().find('.star').addClass('golden')
...
This way you don't bind your javascript to the text inside your elements.
jQuery has a handy trim function:
var modal_counter = div_parent.find('#modal_counter').text().trim();
Try this from your console:
$.trim("\n\nHello\r\nThere\n")
See how it removes the leading and trailing white-space?
Let's say you have:
<p id="modal_1" class="hidden">Img 1</p>
you can extract the number both using:
// If you need it from the text
var n = $("[id^=modal_]").text().match(/\d+/); // 1
or
// If you need it from the ID
var n = $("[id^=modal_]")[0].id.match(/\d+/); // 1
Than to target the image like:
<img id="image_1" src="someimage.jpg" alt="SEO">
you do:
$('#image_'+ n)
If you really just have:
<p id="modal_counter" class="hidden">3</p>
than you can do:
var n = $('#modal_counter').text(); // "3"
$("#image_"+ n) // .fadeIn() or whatever...
Just make sure you don't have duplicate modal_counter ID elements on your page. ID has to be unique.

How to use arrays in javascript to match up divs when event fires?

I have a set of two divs - First set: when people mouse over these divs, it will fire an event, Second set: when the event is fired, these divs will be displayed.
When you mouse over a div in the first set, it should display its corresponding div in the second set. I thought an easy way to match the mouseover divs with the correct div to display would be using arrays. I've been able attach the event listeners properly, but I can't figure out how to set it up so that when you mouseover one object of an array, it displays the array object with the same index number. I think if I could figure out how to recoginze the index number of the object I am mousing over, I could get it to work. I've tried a lot of things, but haven't been able to create anything that works. Here's the code:
<script>
$(document).ready(function(){
//create array of divs to mouse over
var ar = new Array();
ar[0] = $("#home");
ar[1] = $("#doc");
var length = ar.length;
//create array of divs to display when event is fired
var des = new Array();
des[0] = $("#homeDes");
des[1] = $("#docDes");
// start for
for ( var i = 0; i< length; ++i )
{
ar[i].bind("mouseover",function(){$(des[i]).css("display","block");});
ar[i].bind("mouseout",function(){$(des[i]).css("display","none");});
}
//end for
});
//end
</script>
I would tend toward making a more flexible approach to this so that you don't need to change your javascript when you change your HTML. Consider classing your elements that need to have the bindings and providing data attribute to specify the target. Your HTML for divs to be bound might look like this:
<div id="home" class="mouseoverToggleTrigger" data-target="#homeDes">...</div>
And the jQuery might look like this:
$(document).ready(function(){
$('.mouseoverToggleTrigger').hover(function() {
var $target = $($(this).data('target'));
$target.toggle();
}
});
Note this is assuming you are using HTML5 for which jQuery, by default, converts data-* into values retrievable via data().
For pages that are not HTML5, this more generalized solution will work
$(document).ready(function(){
$('.mouseoverToggleTrigger').hover(function() {
var $target = $($(this).prop('data-target'));
$target.toggle();
}
});
One additional bit of flexibility this gives, is that you now don't have to limit yourself to a one-to-one trigger to target mapping. You could specify a class name or other jQuery selector for data-target values to get highly customized behavior, such as one trigger toggling all elements of a certain class that are children of another class.
$(document).ready(function(){
//create array of divs to mouse over
var ar = new Array();
ar[0] = $("#home");
ar[1] = $("#doc");
var length = ar.length;
//create array of divs to display when event is fired
var des = new Array();
des[0] = $("#homeDes");
des[1] = $("#docDes");
// start for
for ( var i = 0; i< length; ++i )
{
// WRAP THE BODY OF THE FOR LOOP IN A FUNCTION
function(index) {
ar[index].bind("mouseover",function() {
$(des[index]).css("display","block");}
);
ar[index].bind("mouseout",function() {
$(des[index]).css("display","none");
});
}(i);
}
//end for
});
When the events are fired the value of i is the length of the array, you have to pass the value of i to another function so that in each function scope the value of index will be the value of i when it was called.
A simpler approach code wise is to give the common elements common classes and then use jQuery index() and eq() to match pairings
HTML
<a id="home" class="hoverMe">
<a id="doc" class="hoverMe">
<div id="homeDes" class="content">
<div id="docDes" class="content">
JS
var $content=$('.content')
var $links=$('.hoverMe').hover(function(){
$content.eq( $links.index(this) ).show()
},function(){
$content.eq( $links.index(this) ).hide()
})
index() API Docs
eq() API Docs

load a div with custdata

I am loading a tr onclick the first tr but the problem is each td in the tr should load the different div which is inside the second div. Now the content which is inside the custdata is loading but how do I load the content which is inside the respective div??
Here is the demo
http://jsfiddle.net/FMnTa/6/
I am not sure if this is what you are asking for, but it seems like it.
$(function(){
$(".info").find("img").click(function(){
var trid = $(this).parent().attr("idcust");
var trdata = $(this).parent().attr("custdata");
// Hide all content divs and show only the one related to the click
$("#"+trid).children().hide();
$(trdata).show();
$("#"+trid).css("display","block");
});
});​
Here is a fiddle as well: http://jsfiddle.net/FMnTa/9/
The code could also be somewhat improved like this:
$(function(){
$("img", ".info").click(function(){
var parent = $(this).parent();
var trid = parent.attr("idcust");
var trdata = parent.attr("custdata");
// Hide all content divs and show only the one related to the click
$("#"+trid).show().children().hide();
$(trdata).show();
});
});​
Custom data attributes
When using custom attributes, you should really consider using the custom data attributes (data- attributes) instead. In your case the attributes would be data-idcust and data-custdata.
You could then use jQuery's .data() to get/set the attributes. Given that you name the attribute data-idcust you could read it with .data("custid") and set it with .data("custid", "newValue").
See what happen with this:
$(".info").find("img").click(function(){
var trid = $(this).parent().attr("idcust");
var trdata = $(this).parent().attr("custdata");
$("#"+trid).show().find(trdata).css('border', '1px solid red');
$("#"+trid).show().find(trdata).toggle();
});
find(trdata) find the tr1 div with id trdata

JQuery replace html element contents if ID begins with prefix

I am looking to move or copy the contents of an HTML element. This has been asked before and I can get innerHTML() or Jquery's html() method to work, but I am trying to automate it.
If an element's ID begins with 'rep_', replace the contents of the element after the underscore.
So,
<div id="rep_target">
Hello World.
</div>
would replace:
<div id="target">
Hrm it doesn't seem to work..
</div>​
I've tried:
$(document).ready(function() {
$('[id^="rep_"]').html(function() {
$(this).replaceAll($(this).replace('rep_', ''));
});
});​
-and-
$(document).ready(function() {
$('[id^="rep_"]').each(function() {
$(this).replace('rep_', '').html($(this));
});
​});​
Neither seem to work, however, this does work, only manual:
var target = document.getElementById('rep_target').innerHTML;
document.getElementById('target').innerHTML = target;
Related, but this is only text.
JQuery replace all text for element containing string in id
You have two basic options for the first part: replace with an HTML string, or replace with actual elements.
Option #1: HTML
$('#target').html($('#rep_target').html());
Option #2: Elements
$('#target').empty().append($('#rep_target').children());
If you have no preference, the latter option is better, as the browser won't have to re-construct all the DOM bits (whenever the browser turns HTML in to elements, it takes work and thus affects performance; option #2 avoids that work by not making the browser create any new elements).
That should cover replacing the insides. You also want to change the ID of the element, and that has only one way (that I know)
var $this = $(this)
$this.attr($this.attr('id').replace('rep_', ''));
So, putting it all together, something like:
$('[id^="rep_"]').each(function() {
var $this = $(this)
// Get the ID without the "rep_" part
var nonRepId = $this.attr('id').replace('rep_', '');
// Clear the nonRep element, then add all of the rep element's children to it
$('#' + nonRepId).empty().append($this.children());
// Alternatively you could also do:
// $('#' + nonRepId).html($this.html());
// Change the ID
$this.attr(nonRepId);
// If you're done with with the repId element, you may want to delete it:
// $this.remove();
});
should do the trick. Hope that helps.
Get the id using the attr method, remove the prefix, create a selector from it, get the HTML code from the element, and return it from the function:
$('[id^="rep_"]').html(function() {
var id = $(this).attr('id');
id = id.replace('rep_', '');
var selector = '#' + id;
return $(selector).html();
});
Or simply:
$('[id^="rep_"]').html(function() {
return $('#' + $(this).attr('id').replace('rep_', '')).html();
});
From my question, my understanding is that you want to replace the id by removing the re-_ prefix and then change the content of that div. This script will do that.
$(document).ready(function() {
var items= $('[id^="rep_"]');
$.each(items,function(){
var item=$(this);
var currentid=item.attr("id");
var newId= currentid.substring(4,currentid.length);
item.attr("id",newId).html("This does not work");
alert("newid : "+newId);
});
});
Working Sample : http://jsfiddle.net/eh3RL/13/

jQuery: Change element type from hidden to input

I've got an input which it's type is set to hidden, I need to change it's type to text. Can't seem to figure this out or if it's possible with jQuery
With jQuery 1.4 you can change the type of an input while it's detached.
marker = $('<span />').insertBefore('#myInput');
$('#myInput').detach().attr('type', 'text').insertAfter(marker);
marker.remove();
I'm not sure this is possible, so I would suggest using a hidden div to contain the input element, which can be shown as needed. The text input field can still hold data even if it's hidden.
IE won't allow you to change the type of a form element for security reasons so I would go with Aram's hidden div suggestion.
Here's how I would do this:
$("input[type='hidden']").each(function(){
var name = $(this).attr('name'); // grab name of original
var value = $(this).attr('value'); // grab value of original
/* create new visible input */
var html = '<input type="text" name="'+name+'" value="'+value+'" />';
$(this).after(html).remove(); // add new, then remove original input
});
If you want to filter some of the elements call filter() before each(), like this:
$("input[type='hidden']").filter("[name='whatever']").each(function...
easy man...
$('input[type="hidden"]').each (function() { this.type = 'text'; });
Trigger it on a event
Overlay.toAnyType = function (c, type) {
var shadow = jQuery(document.createElement(c.context.nodeName));
// Clone attributes to new object.
for (var i = 0; i < c[0].attributes.length; i++) {
var attr = c[0].attributes[i].name;
var val = c[0].attributes[i].value;
if (attr == "type") val = type;
shadow.attr(attr, val);
}
shadow.insertAfter(c);
c.remove();
};
When c is a jQuery object; the function above changes type attribute. Usage:
var inputElemt = jQuery("#input");
Overlay.toAnyType(inputElemt, "text");
Old thread, but I recently needed to do something similar but with file fields and clearing them... I think the same solution could apply, but at least you can grab the contents in this case.
var temp = $('#hidden-field').val();
$("#container-for-field").html("<input id='not-hidden' type='text' value='"+temp+"'/>");
That should also solve the problem :).

Categories

Resources