Nested dynamically added content - javascript

I'm creating a form which allows the users to add additional content on the fly. The structure of the form is such that there are three dimensions to the form data, i.e., like a movie can play at different theatres and each theatre can have different showing times. The form, therefore has grandparent, parent and child divs, and the parent & child divs can be added to on the press of a button.
Here's a slimed-down version of the code for clarity
<div id="grandparent">
<div id="parent">
Parent 1
<div id="child">
Child 1
</div>
</div>
<button id="addChild">Add Child</button>
</div>
<button id="addParent">Add Parent</button>
<script>
$(function() {
var grandparent_div = $('#grandparent');
var parent_div = $('#parent');
var child_div = $('#child');
var p = $('#grandparent div#parent').size() + 1;
var c = $('#parent div#child').size() + 1;
$('#addChild').on('click', function() {
$('<div id="child">Child '+c+'</div>').appendTo(parent_div);
});
$('#addParent').on('click', function() {
$('<div id="parent">Parent '+p+'<div id="child">Child 1</div><button id="addChild">Add Child</button></div>').appendTo(grandparent_div);
});
});
</script>
JSFiddle here: http://jsfiddle.net/u2vUT/
I can create parent nodes fine, and I can even create child nodes of parents on the first level - the problem comes when trying to add children of dynamically-added parents. It's probably because the 'addChild' button is no longer unique, so $('#addChild').on('click') can't reference it. So, is there a way to make this work (preferably elegant!)?

You should not use ids, use class
<div id="grandparent">
<div class="parent">Parent 1
<div class="child">Child 1</div>
</div>
<button class="addChild">Add Child</button>
</div>
<button id="addParent">Add Parent</button>
then
$(function () {
var grandparent_div = $('#grandparent');
var parent_div = $('.parent');
var child_div = $('.child');
var p = grandparent_div.find('.parent').size() + 1;
grandparent_div.on('click', '.addChild', function () {
$('<div id="child">Child ' + ($(this).siblings().length + 1) + '</div>').insertBefore(this);
});
$('#addParent').on('click', function () {
$('<div class="parent">Parent ' + p + '<div class="child">Child 1</div><button class="addChild">Add Child</button></div>').appendTo(grandparent_div);
});
});
Demo: Fiddle

Related

Hide parent element based on value of child element

I want to create a filter function which hides divs based on values of p tags. The behavior should be the following:
User selects a filter, e.g. >5:
Loop through all p-tags with a certain class
If the value within the p-tag matches the filter (>5), hide all parent divs of each p-tag which value doesn't match the filter value
My solution is the following:
function eraseThis() {
counter = 0
tagList = document.getElementsByClassName("rating")
$(".rating").each(function()
{
if (this.innerHTML < 5) {
$(this).parent().hide()
}
counter = counter + 1
});
}
This gives me the results I'm looking for but I'm wondering if there's a more elegant / efficient way to do it ?
The markup would be something like:
<div class="movie">
<p class="rating"> some value </p>
</div>
<div class="movie">
<p class="rating"> some value </p>
</div>
and so on
I think this should do the trick :
JQuery code :
function eraseThis() {
var tagList = $(".rating");
tagList.each(function(){
var $this = $(this);
if (parseInt( $this.text() ) < 5) {
$this.parent().hide();
}
});
}
Html code :
<div class="movie">
<p class="rating">2</p>
</div>
<div class="movie">
<p class="rating">9</p>
</div>
And here is the full code : JSFiddle

How to add working dropify inputs dynamically

I have form which gets clone when user click on add more button .
This is how my html looks:
<div class="col-xs-12 duplicateable-content">
<div class="item-block">
<button class="btn btn-danger btn-float btn-remove">
<i class="ti-close"></i>
</button>
<input type="file" id="drop" class="dropify" data-default-file="https://cdn.example.com/front2/assets/img/logo-default.png" name="sch_logo">
</div>
<button class="btn btn-primary btn-duplicator">Add experience</button>
...
</div>
This my jquery part :
$(function(){
$(".btn-duplicator").on("click", function(a) {
a.preventDefault();
var b = $(this).parent().siblings(".duplicateable-content"),
c = $("<div>").append(b.clone(true, true)).html();
$(c).insertBefore(b);
var d = b.prev(".duplicateable-content");
d.fadeIn(600).removeClass("duplicateable-content")
})
});
Now I want every time user clicks on add more button the id and class of the input type file should be changed into an unique, some may be thinking why I'm doing this, it I because dropify plugin doesn't work after being cloned, but when I gave it unique id and class it started working, here is what I've tried :
function randomString(len, an){
an = an&&an.toLowerCase();
var str="", i=0, min=an=="a"?10:0, max=an=="n"?10:62;
for(;i++<len;){
var r = Math.random()*(max-min)+min <<0;
str += String.fromCharCode(r+=r>9?r<36?55:61:48);
}
return str;
} var ptr = randomString(10, "a");
var className = $('#drop').attr('class');
var cd = $("#drop").removeClass(className).addClass(ptr);
Now after this here is how I initiate the plugin $('.' + ptr).dropify().
But because id is still same I'm not able to produce clone more than one.
How can I change the id and class everytime user click on it? is there a better way?
Working Fiddle.
Problem :
You're cloning a div that contain already initialized dropify input and that what create the conflict when you're trying to clone it and reinitilize it after clone for the second time.
Solution: Create a model div for the dropify div you want to clone without adding dropify class to prevent $('.dropify').dropify() from initialize the input then add class dropify during the clone.
Model div code :
<div class='hidden'>
<div class="col-xs-12 duplicateable-content model">
<div class="item-block">
<button class="btn btn-danger btn-float btn-remove">
X
</button>
<input type="file" data-default-file="http://www.misterbilingue.com/assets/uploads/fileserver/Company%20Register/game_logo_default_fix.png" name="sch_logo">
</div>
<button class="btn btn-primary btn-duplicator">Add experience</button>
</div>
</div>
JS code :
$('.dropify').dropify();
$("body").on("click",".btn-duplicator", clone_model);
$("body").on("click",".btn-remove", remove);
//Functions
function clone_model() {
var b = $(this).parent(".duplicateable-content"),
c = $(".model").clone(true, true);
c.removeClass('model');
c.find('input').addClass('dropify');
$(b).before(c);
$('.dropify').dropify();
}
function remove() {
$(this).closest('.duplicateable-content').remove();
}
Hope this helps.
Try this:
$(function() {
$(document).on("click", ".btn-duplicator", function(a) {
a.preventDefault();
var b = $(this).parent(".duplicateable-content"),
c = b.clone(true, true);
c.find(".dropify").removeClass('dropify').addClass('cropify')
.attr('id', b.find('[type="file"]')[0].id + $(".btn-duplicator").index(this)) //<here
$(c).insertBefore(b);
var d = b.prev(".duplicateable-content");
d.fadeIn(600).removeClass("duplicateable-content")
})
});
Fiddle
This does what you specified with an example different from yours:
<div id="template"><span>...</span></div>
<script>
function appendrow () {
html = $('#template').html();
var $last = $('.copy').last();
var lastId;
if($last.length > 0) {
lastId = parseInt($('.copy').last().prop('id').substr(3));
} else {
lastId = -1;
}
$copy = $(html);
$copy.prop('id', 'row' + (lastId + 1));
$copy.addClass('copy');
if(lastId < 0)
$copy.insertAfter('#template');
else
$copy.insertAfter("#row" + lastId);
}
appendrow();
appendrow();
appendrow();
</script>
Try adding one class to all dropify inputs (e.g. 'dropify'). Then you can set each elements ID to a genereted value using this:
inputToAdd.attr('id', 'dropify-input-' + $('.dropify').length );
Each time you add another button, $('.dropify').length will increase by 1 so you and up having a unique ID for every button.

bind multi JqGrid inside the page

i have to bind jqGrids inside an accordion (JQ UI) and here is my code :
here i draw the grid inside the accordion .
<div id="accordion" class="accordion-style2">
<div class="group">
#foreach (var mytable in lstmytable )
{
<h3 class="accordion-header">mytable.DAY_NAME</h3>
<div divgrid="true" id="myDiv_#mytable.DAY_ID">
<p>
<table grid="true" id="grid_table_#mytable.DAY_ID"></table>
<div pagerid="true" id="grid-pager_#mytable.DAY_ID"></div>
</p>
</div>
}
</div>
</div>
//here i get the ids from the grid and the pager
$("[divgrid='true']").each(function () {
var GridID = jQuery(this).find("table").attr("id");
var PagerID = jQuery(this).find("div").attr("id");
BindGrid(GridID, PagerID);
});
//here i bind the grids using different id each time .
BindGrid(gridID,PagerID)
{
var grid_selector = GridID;
var pager_selector = PagerID;
//my grid implementation
}
but it never bind any grid
i find out that the grid_selector need to be have a # before it to become like this
var grid_selector = "#" + GridID;
var pager_selector = "#" + PagerID;

Simpler Javascript counter

I need some help with the click event, I'm trying to have an individual counter that is incremented by the click event that I have on the img. I've tried many variations, I want to resolve this without using jQuery.
<script async>
var count = 0;
var clickerCount = document.getElementsByClassName('clicker');
var cat = {
count : 0,
counter: function(){
this.count++;
clickerCount.textContent = "Kitten Click Count :" + this.count;
console.log("counter function working");
console.log(cat.count);
}
};
function modifyNum(){
cat.counter();
console.log("modifyNum function working");
}
</script>
</head>
<body>
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="cat0" onclick="modifyNum();">
<p id='clicker'>Kitten Click Count :</p>
</div>
<div>
<img src="http://placekitten.com/200/296" id='cat1' onclick="modifyNum();">
<p id='clicker'>Kitten Click Count :</p>
</div>
</div>
For a start, you are using id='clicker' in two places (IDs are supposed to be unique), and then using document.getElementsByClassName, which returns nothing because you used an ID and not a class.
Once you do change it to a class, document.getElementsByClassName will return an array of elements. You'll have to use clickerCount[0] and so on, or loop through the array.
This example should work. I've separated the HTML from the Javascript because it looks clearer for me. You can use it as an example to expand / create your own in your own way.
Hope it help
HTML:
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="1" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-1">0</span>
</div>
<div>
<img src="http://placekitten.com/200/296" id="2" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-2">0</span>
</div>
</div>
JS:
var imagesCountable = document.getElementsByClassName("countable");
var counters = [];
for (var i = 0; i < imagesCountable.length; i++) {
counters[imagesCountable[i].id] = 0;
imagesCountable[i].onclick = function(e) {
document.getElementById("counter-for-" + e.currentTarget.id)
.innerHTML = ++counters[e.currentTarget.id];
}
}
var imagesCountable = document.getElementsByClassName("countable");
var counters = [];
for (var i = 0; i < imagesCountable.length; i++) {
counters[imagesCountable[i].id] = 0;
imagesCountable[i].onclick = function(e) {
var cElem = document.getElementById("counter-for-" + e.currentTarget.id);
cElem.innerHTML = ++counters[e.currentTarget.id];
}
}
<div style="display:inline">
<div>
<img src="http://placekitten.com/200/296" id="1" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-1">0</span>
</div>
<div>
<img src="http://placekitten.com/200/296" id="2" class="countable">
<span>Kitten Click Count :</span><span id="counter-for-2">0</span>
</div>
</div>
I have solved this problem in this JSFiddle!
If you can hardcode the IDs then it's easier in my point o view to just manipulate things by ID.
<div>
<img src="http://placekitten.com/200/296" id="cat0" onclick="counter(0);">
<p id='clicker0'>Kitten Click Count :</p>
<input type="hidden" id="counter0" value="0">
</div>
function counter(id) {
var cnt = parseInt(document.getElementById("counter" + id).value);
cnt++;
document.getElementById("counter" + id).value = cnt;
document.getElementById('clicker' + id).innerHTML = 'Kitten Click Count :' + cnt;
}
It's not the same approach but I find it easy to understand.
Hope it helps.
Ok, so first off you have two elements with the id of 'clicker'. You probably meant for those to be classes and ids. So when you call modifynum() it cant locate those because the class doesn't exists. Second, your JS is loading before your HTML elements. So when the JS gets to this line:
var clickerCount = document.getElementsByClassName('clicker');
It is going to find nothing, even if you correct the class names. So you want to move your JS to the footer of your HTML document, or wrap the code in a method that is called on pageLoad().
I think that should take care of it. Your object, for the most part, looks correct.

How to find the deepest child of a div with jquery

I'm trying to find the deepest element in the specified divwith jquery. But the code which used is producing the error TypeError: parent.children is not a function.
I found this code from this link
the code is :
function findDeepestChild(parent) {
var result = {depth: 0, element: parent};
parent.children().each( //Here I getting the error TypeError: parent.children is not a function
function(idx) {
var child = $(this);
var childResult = findDeepestChild(child);
if (childResult.depth + 1 > result.depth) {
result = {
depth: 1 + childResult.depth,
element: childResult.element};
}
}
);
return result;
}
---------------------------------------------------------------------------------------
$(document).on('keypress','#sendComment', function(e) {
if(e.keyCode==13){
var itemId=$('#findbefore').prev('.snew').attr('id');//
var item=findDeepestChild(itemId);
alert(item);
}
});
And my divs are :
<div id="S04" class="snew" style="display: block;">
<div class="author-image"></div>
<span>xyz shared the image xyz</span>
<div class="s-content">
<div class="s-message"></div>
<div class="shpicture">
<img class="SharedImage" width="100%" height="100%" data-shareid="1" data-alid="1" data-id="1" alt="xyz" src="data:image/jpeg;base64,">
</div>
</div>
</div>
<div class="SPcommentbox">
<div class="comment">
<div class="commenter-image"></div>
<div class="addcomment">
<input class="commentbox" type="text" placeholder="Write a comment...">
</div>
</div>
</div>
I need to find the img from these.
please anyone help me .... Thanks ...
To get the deepest nested elements, use
$("#" + parent).find("*").last().siblings().addBack()
http://jsfiddle.net/6ymUY/1/
you can then get the id data attribute with
item.data("id")
http://jsfiddle.net/6ymUY/2/
full code:
function findDeepestChild(parent) {
return $("#" + parent).find("*").last().siblings().addBack();
}
var item=findDeepestChild("S04");
console.log(item)
console.log(item.data("id"));
You're calling it with a string, but it's expecting a jQuery instance.
Instead of
var itemId=$('#findbefore').prev('.snew').attr('id');//
var item=findDeepestChild(itemId);
you probably want
var item=findDeepestChild($('#findbefore').prev('.snew'));
You are passing in itemId, which is the ID attribute of a given element. I think what you meant to pass was the element itself. Just remove the attr call, leaving this:
var item = findDeepestChild($("#findbefore").prev(".snew"));

Categories

Resources