Appending child nodes on a div - javascript

Im trying to add items into a div element based on elements from an array.
The element I'm trying to add already exists on the page. Basically I'm trying to just create a new version of it and add it to the div.
The code might help explain things further.
JavaScript:
function apply(list) {
var item = $("#it_template").children("md-list-item").eq(0);
for(var i = 0; i < list.uuids.length; i++){
var uid = list.uuids[i];
item.children("p").eq(0).html(uid);
$("#items").append(item);
}
}
HTML:
<div id="items">
</div>
<div style="display:none" id="it_template">
<md-list-item md-ink-ripple class="list_item">
<p></p>
</md-list-item>
</div>
It seems to be faulty somewhere, since whenever I'm running the code I'm only seeing one item being added to the div.
Can you please help me out with where the error is?

Try this? The important change is cloning the node instead of trying to append it over and over. (A node can only have one parent, so it will just get moved instead of copied.)
Another change I made was to use .text instead of .html. If you're dealing with text, this is generally much better. (Importantly, it reduces your risk of XSS vulnerabilities.)
function apply(list) {
var item = $("#it_template").children("md-list-item").eq(0);
for(var i = 0; i < list.uuids.length; i++) {
var uid = list.uuids[i];
var newItem = item.clone();
newItem.children("p").eq(0).text(uid);
$("#items").append(newItem);
}
}

Unless you are Using Angular Material, <md-list-item> is an invalid tag.
Sorry, i am not sure what you are attempting to do but if you want to fill something with a collection of somethings and you want to use Angular. Check out NG-REPEAT directive.

Related

Way to differentiate multiple divs with same class or ID when Javascript is run

I am generating QR codes for [id] on an invoice.
Right now I have a javascript at each place where there is going to be a qr code to run, and generate the code.
<script type="text/javascript">
function makeCode (data,width) {
var qrcode = new QRCode(document.getElementById(data), {
width : width,
height : width
});
var length = (data).length;
if (length===10) {qrcode.makeCode("10" + data);}
else {qrcode.makeCode(data);}
}
</script>
<div id="[id]"></div><script>makeCode("[id]","50")</script>
The reason I have to use [id] as the "id" of the div is that it's the only piece of dynamic content I get for the item.
The issue is that when I have more than one item with the same [id] the javascript is of course stacking up all the QR codes into the first <div> with that id.
Is there a way to have the javascript know that it was run from the third DIV (as an example) and then put the code into the third DIV, instead of the first.
I know that you're not supposed to have more than one div with the same ID element. That's part of the issue, I am trying to make them unique but I dont know how.
I have added a jfiddle so you can see the issue a little more clearly.
https://jsfiddle.net/nmteaco/x57o9pko/3/
As mentioned, few things in your current website logic needs to adjust to more dynamic.
First, should have one table which represent shopping cart and within that cart, you can have multiple rows of items for QRcode generation. And each same id can have a indexing flag 1..2..3..
I have made a demo of how your issue can be fixed with change of your html structure.
Demo
Let me know what you think.
I dont know how this worked...
However adding a class to the products of "product" and posting the following code at the end of the document worked.
$.each($(".product"), function(index, value){
var num = index + 1;
$(value).attr("id","qrcode"+ num);
});
It makes each id unique after it runs. However somehow the qr javascript still knows which div to put the correct image into.
Change your html to this:
<div data-content="qr-content" data-value="Your qr content"></div>
<script>
var elements = document.queryselectorall('[data-content="qr-content"]');
for (var i=0; i<elements.length; i++)
makeCode(elements[i].getAttribute('data-value'), 50);
}
</script>

ng-click added by filter to image not working

I have data being added in through a json feed and that data goes through a filter to tidy it up / add some extra elements which all works fine. However I've added a new filter to find images and add ng-click to the markup to do full screen modal images, annoyingly the click event never fires.
.filter('html_filters', function ($sce) {
return function (text) {
var htmlObject = document.createElement('div');
htmlObject.innerHTML = text;
var imgs = htmlObject.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
var link = imgs[i].getAttribute('src');
imgs[i].setAttribute('ng-click', 'loadImage("' + link + '")');
}
return $sce.trustAsHtml(htmlObject.outerHTML);
}
})
HTML:
<p class="postcon arrow-list" ng-if="content" ng-bind-html="content | html_filters"></p>
Rendered HTML:
<img class="aligncenter" src="http://www.sdssdsdsdsd.co.uk/connect/wp-content/uploads/2016/08/sdsdsd-August-20162-1.jpg" alt="Exhibit 1" ng-click="loadImage("http://www.sdssdsdsdsd.co.uk/connect/wp-content/uploads/2016/08/sdsdsd-August-20162-1.jpg")">
Click Event:
$scope.loadImage = function (url) {
console.log("Loading Image");
}
That log event never fires
DOM manipulation should be done inside a directive and not a filter. You can still use a filter inside a directive and leverage the compile phase which will cause your html to be rendered correctly with events and everything.
here is a good explanation of their difference and how to use them:
http://www.c-sharpcorner.com/UploadFile/cd7c2e/directive-and-filter-service-in-angularjs/
UPDATE:
Alright let's make this a bit simpler by looking at your problem from a different angel.
What you are trying to do is iterate over a list of objects you are getting from your json feed and create a bunch of html elements (p and img and ...).
I am going to write this using an ng-repeat (which is a directive right?):
<div ng-repeat="content in jsonList">
<p class="postcon arrow-list" ng-if="content" ng-bind="content.text"></p>
<img class="aligncenter" ng-src="content.url" alt="{{contnt.alt}}" ng-click="loadImage(content.url)">
</div>
So now we have our list of elements when the page is rendered. So what happens to your tidying up logic here. Now is the time to look at filters. Let's suppose you have a filter like below which gets your list and returns the tided up one:
app.filter('myFilter', function () {
return function (jsonList) {
var modifiedList = [];
//your logic goes here
return;
};
});
Now if you want to use this to modify your initial array before parsing the html you can use it like this (by adding it as a filter after your ng-repeat):
<div ng-repeat="content in jsonList | myFilter">
Hope this makes since.
BTW: I didn't want you to change your logic or anything. This is just to let you know the differences and where to use each of them.

Get DOM Element with jQuery

I have a web page that is structured like this:
<canvas id="myCanvas"></canvas>
#for(var i=0; i<10; i++) {
<div class="my-element">
<canvas></canvas>
</div>
}
This code generates one main canvas. Below it, 10 other dynamically generated divs are being generated. In reality, this loop is just used to show that I have some code being dynamically generated. The main thing to understand is the my-element piece.
In my javascript, I have the following:
$(function() {
var mainCanvas = document.getElementById('myCanvas');
initializeCanvas(mainCanvas); // This works.
var dynamicElements = $('.my-element');
for (var i=0; i<dynamicElements.length; i++) {
initializeCanvas($(dynamicElements[i])[0]); // This does not work
}
});
function initializeCanvas(canvas) {
// do stuff
}
The first call to initializeCanvas works because I'm passing in an actual HTML Dom element. But the second initializeCanvas, which is called multiple times, fails because it's passing in something else. How do I get the same type of element as what's returned by document.getElementById in this case?
Thanks!
First of all, this doesn't make sense:
$(dynamicElements[i])[0]
You are getting jQuery element, unwrapping it, then wrapping again in jQuery...
what you simply need to do is get canvas from the element
dynamicElements.eq(i).find('canvas')[0] should do the job
You can't use the same element for this purpose. I suggest you to clone it. Like;
var dynamicElements = $('.my-element').clone();
Also when you add more element with my-element class this will be messy. You should make sure to select only one element with $('.my-element') selection.

writing reusable code to create a like button that increments

For some practice this week, I tried creating the front end of a blog page. I added a few "fake" Like buttons (they don't attach to facebook, just raise a counter that's placed next to them.)
Everything works, though I think there's a more direct and re-usable way to write the jQuery/JavaScript code I used to build those counters.
Here's the JavaScript code:
<script>
var whichButton = "";
var counter = 0; // Adds counters next to each
var counter2 = 0; // "Like" button, and raises
$("button").on("click", function(){ // their values separately.
whichButton = this.id;
if (whichButton === "button1") {
counter++;
$("#span1").html(counter);
} else {
counter2++
$("#span2").html(counter2);
}
});
</script>
...and here's the html it affects:
<button id="button1">Like</button>
<span id="span1"></span>
<button id="button2">Like</button>
<span id="span2"></span>
Is there a less hands-on way to write this code? Something that would allow me to
add new buttons alongside new spans, both with complementary ids, and, without updating my JavaScript code, have my site allow each button to function automatically?
I'm trying to write this in the most efficient way I can.
Thanks!
To make this a more reusable component, take advantage of classes instead of unique IDs.
$(".like_button button").on("click", function() {
var $count = $(this).parent().find('.count');
$count.html($count.html() * 1 + 1);
});
In your markup, create as many like_button instances as you want, and use the HTML to set the default value of 0.
<div class="like_button">
<button>Like</button>
<span class="count">0</span>
</div>
Note: $(this).parent().find('.count'); is a very literal traversing example. You could use $(this).next(); instead to find the button's next sibling, which would remove the need for the "count" class. Check out the jQuery Docs on Traversal for many other wonderful methods.
Here's a fiddle showing that in action: http://jsfiddle.net/bw5LU/
Sure, mark all the like buttons with a class or other attribute so we can select like:
$(".like-button").on("click", function(e){
var $counter = $(this).find(".count");
var count = $counter.text() | 0; //corose current count to an int
$counter.text(count + 1);//set new count
});
Now to create new like buttons add the following snippet anywhere in your html document:
<div class="like-button">
<button>Like</button>
<span class="count"></span>
</div>

Get all html between two elements

Problem:
Extract all html between two headers including the headers html. The header text is known, but not the formatting, tag name, etc. They are not within the same parent and might (well, almost for sure) have sub children within it's own children).
To clarify: headers could be inside a <h1> or <div> or any other tag. They may also be surrounded by <b>, <i>, <font> or more <div> tags. The key is: the only text within the element is the header text.
The tools I have available are: C# 3.0 utilizing a WebBrowser control, or Jquery/Js.
I've taken the Jquery route, traversing the DOM, but I've ran into the issue of children and adding them appropriately. Here is the code so far:
function getAllBetween(firstEl,lastEl) {
var collection = new Array(); // Collection of Elements
var fefound =false;
$('body').find('*').each(function(){
var curEl = $(this);
if($(curEl).text() == firstEl)
fefound=true;
if($(curEl).text() == lastEl)
return false;
// need something to add children children
// otherwise we get <table></table><tbody></tbody><tr></tr> etc
if (fefound)
collection.push(curEl);
});
var div = document.createElement("DIV");
for (var i=0,len=collection.length;i<len;i++){
$(div).append(collection[i]);
}
return($(div).html());
}
Should I be continueing down this road? With some sort of recursive function checking/handling children, or would a whole new approach be better suited?
For the sake of testing, here is some sample markup:
<body>
<div>
<div>Start</div>
<table><tbody><tr><td>Oops</td></tr></tbody></table>
</div>
<div>
<div>End</div>
</div>
</body>
Any suggestions or thoughts are greatly appreciated!
My thought is a regex, something along the lines of
.*<(?<tag>.+)>Start</\1>(?<found_data>.+)<\1>End</\1>.*
should get you everything between the Start and end div tags.
Here's an idea:
$(function() {
// Get the parent div start is in:
var $elie = $("div:contains(Start)").eq(0), htmlArr = [];
// Push HTML of that div to the HTML array
htmlArr.push($('<div>').append( $elie.clone() ).html());
// Keep moving along and adding to array until we hit END
while($elie.find("div:contains(End)").length != 1) {
$elie = $elie.next();
htmlArr.push($('<div>').append( $elie.clone() ).html());
};
// htmlArr now has the HTML
// let's see what it is:
alert(htmlArr.join(""));
});​
Try it out with this jsFiddle example
This takes the entire parent div that start is in. I'm not sure that's what you want though. The outerHTML is done by $('<div>').append( element.clone() ).html(), since outerHTML support is not cross browser yet. All the html is stored in an array, you could also just store the elements in the array.

Categories