How to create html id attributes dynamically? - javascript

Im trying to display multiple charts.
Right now, I have <canvas id="pie-chart"> inside a loop and document.getElementById("pie-chart") will only return the first element with that id. How do I create a dynamically html attribute?
<table class="table">
<tr>
<th>
Questions
</th>
</tr>
#foreach (var question in (List<Testv3.Models.MyViewModel>)ViewData["questionlist"])
{
<tr>
<td>
#question.Question
<br />
<div class="chart">
<canvas id="pie-chart"></canvas>
</div>
</td>
</tr>
}
</table>
A part of my script section:
var ctx1 = document.getElementById("pie-chart").getContext("2d");

I'm not totally sure what you are using to render your HTML since your code doesn't look like pure HTML to me. However, the answer stays the same, you can use the index of the loop as a part of your id to make it unique. Something like this:
<canvas id="pie-char-#id></canvas>
with #id is your index of the loop.
If your current renderer doesn't support that, you may want to add a counter outside of the loop, use that counter as part of your id. Then increase the counter at the end of the loop.

See Does ID have to be unique in the whole page?
The HTML Id needs to be unique in your whole HTML-Instance. Use "class" instead of "id".
Id is and was never designed to be used multiple times. Id is designed to be a unique identifier.

Related

.each() function on affect current object

having some issues with my code below, first here is the HTML:
<table class="finance-table">
<tbody><tr>
<th></th>
<th>Deposit</th>
<th>Balance</th>
<th>Fees</th>
<th>Total Payable</th>
<th>Term</th>
<th>Fixed Rate</th>
<th>Representative APR</th>
<th>Monthly Pmt</th>
</tr>
<tr class="hp">
<td><strong>HP</strong></td>
<td id="td_finance_deposit">£11700.00</td>
<td id="td_finance_balance">£105300.00</td>
<td id="td_finance_fees">£298.00</td>
<td id="td_finance_total_inc_deposit">£146255.50</td>
<td id="td_finance_term">60 mths</td>
<td id="td_finance_rate">5.50%</td>
<td id="td_finance_apr">10.1%</td>
<td id="td_finance_monthly_payments">£2242.59 p/m* x 60 mths</td>
</tr>
</tbody></table>
There is about 10 of these tables [within the same document], all with the same id's and class's. I'm using an each loop to execute some code against each table found, however it only seems to be working on the first table and disregards the others.
Below is the jQuery, like I said works find on the first table, but ignores the rest!
<!-- Remove First and Final Payment from Showroom Finance Examples -->
<script>
$(".finance-table").each(function(key, value) {
// Display loading
var html = $(this);
// Remove the First Payment and Final Payment Column
$(this).find("#td_finance_first_payment, #td_finance_final_payment").remove();
$(this).find("th:contains('1st Pmt')").remove(); $(this).find("th:contains('Final Pmt')").remove();
// Get the Term and update the monthly payment
var term = $(this).find("#td_finance_term").html(); // .replace(/\D/g,'')
var payments = ($(this).find("#td_finance_monthly_payments").html()).split('x')[0];
($(this).find("#td_finance_monthly_payments")).html(payments + " x " + term);
})
</script>
Edit:
Please note, I can't change the HTML at all
You should first give a unique ID to each <td>, perhaps with your DB identifier for that record. You don't need it now but this will allow you to do other thing later if you need it.
Then change all the <td> ids to classes:
<td class="td_finance_fees">£298.00</td>
Finally change all your javascript accordingly to use class instead of IDs:
$(this).find(".td_finance_first_payment, .td_finance_final_payment").remove();
Using Attribute Equals Selector
Change your code from:
$(this).find("#td_finance_first_payment, #td_finance_final_payment").remove();
to:
$(this).find('td[id="td_finance_first_payment"], td[id="td_finance_final_payment"]').remove();
Do this type of change for all areas of #xxx to id="xxx"
What this does is find all tds with attribute id="xxx", rather than using #id identifier, this is forces jQuery to do a tree search.
Also your HTML does not match your code, (theres no td_finance_first_payment in your html, I assume you removed it?)
Edit: This solution is useful if you 100% cannot edit the html (comes from a source you have no control over, such as an API or internal software). Best solution would be to fix the ids!

Make html layout and use it with JS

I have a table with some data:
<table id="myTable">
<thead>
<tr>
<th><h1>Name</h1></th>
<th><h1>Picture</h1></th>
<th><h1>Likes</h1></th>
<th><h1>Time</h1></th>
</tr>
</thead>
<tbody>
***loop***
<tr>
<td>{placeholder1}</td>
<td><img src="{placeholder2}" alt=""></td>
<td>{placeholder3}</td>
<td>{placeholder4}</td>
</tr>
***end loop***
</tbody>
</table>
I have a js function who gets some data from server by POST request every 10 minutes. <tr></tr> block needs to be repeated several times.
HTML code become more and more complex and I need a solution with layouts and placeholders. I need a direction to search :)
All I need is:
Store <tr></tr> pattern with placeholders to insert it into my webpage. How could I achieve it with js?
How could I mark the places where I need data to be inserted?
Okay since you are using jQuery,
This may be your HTML
<table>
<tbody id="myTableBody">
<!-- Your elements will be placed here -->
</tbody>
</table>
I will assume you are using $.ajax or $.post in either of those, add a callback function property success
$.ajax({
// ... your properties,
success: function(data) {
// basic template for of your "tr"
var trTemplate = [
'<tr>',
'<td></td>',
'<td><img src="" alt=""></td>',
'<td></td>',
'<td></td>',
'</tr>'
].join('')
// get the tbody elemen
var $myBody = $('#myTableBody')
// if you want to clean up the current content of $myBody,
// if it is not the case just remove the following line
$myBody.empty()
// assuming data is an array of elements / entities
data.forEach(function(element){
var $tr = $(trTemplate)
$tr.find('td').eq(0).text(element.placeholder1)
$tr.find('img').attr('src', element.placeholder2)
$tr.find('td').eq(2).text(element.placeholder3)
$tr.find('td').eq(3).text(element.placeholder4)
$myBody.append($tr)
})
}
})
This is example of how you could do it, there are many ways to improve this for performance and so on. Please use it only as reference
If you're using jQuery then this is pretty straightforward. You need to id your elements so that you can reference them individually. Say you start with:
<tr id="tr-0" >
content...
</tr>
and then in javascript..
var id = $('#tr-0').attr('id');
var num = parseInt(id.substring(3));
num++;
$('#tr-0').after('<tr id='+num+'>content...</tr>');
obviously you need to figure how you're getting the content for each row but hopefully you can see that it wouldn't be too hard to fill each row with custom data.
Although you can use jQuery, simpler ways exist. jQuery will require you to add additional steps that aren't really necessary. If you want to use as few Javascript packages as possible, go with jQuery.
But, I highly recommend Vue.js for Laravel projects. There are instructions from Laracasts on how to set it up. But, I have created a jsfiddle with a working set of Vue.js with the v-for directive. Checkout the JSFiddle here.
If you have questions, I'll answer as much as I can.

How to identify xpath of an element which do not have any attribute information

I want to identify an element which is a text "My Portal" from td tag. Below is my HTML
<tbody>
<tr>
<td>
<!-- rendered always true, custom column names are also label -->
My Portal
<!-- rendered always false, this feature is not required -->
</td>
</tr>
</tbody>
I have tried below xpaths as shown below, but none of them works:
1. .//td[text()="My Portal"]
2. .//td[contains(text(),"My Portal")]
After some search in the internet I found normalize-space() method which will remove the trailing and unnecessary white spaces. I have tried the method using the below xpath
.//td[normalize-space()="My Portal"]
Am able to identify the element, but in the firebug it is showing as 2 matching nodes. Please find the attachment for the highlighted elements in the firebug
My questions are:
Why two tags are getting highlighted?
Why .//td[contains(text(),"My Portal")] does not work?
How to identify the "My Portal" uniquely?
Can anyone please help?
There are several solutions. An efficient approach is to specify the exact path from the root node to the td you want. Something like
/html/body/table/tbody/tr/td/table/tbody/tr/td[normalize-space()='My Portal']
If you know that there are no more than two nesting tables, you can shorten this to
//td//td[normalize-space()='My Portal']
If you want the td in the innermost table regardless of table structure, try
//td[not(.//table) and normalize-space()='My Portal']
This isn't very efficient though. If you know that the text "My Portal" appears in an immediate text child of td, try
//td[text()[normalize-space()='My Portal']]
To uniquely identify the second td, what you have to do is add an additional filter. So if you look at the difference between the 2 tags highlighted, the parent has a class and the child doesn't. So if you need the second td, the xpath would be //td[normalize-space()='My Portal' and not(#class='rich-table-cell')]
If you need the parent then: //td[normalize-space()='My Portal' and #class='rich-table-cell']
Instead of using text() try .
.//td[contains(.,"My Portal")]
To Answer your questions:
1- Because you are using a global selector, "//", with this selector XPAth will find all the elements into the tree, so if you want select only one td you should specific the path, something like this
/table/tbody/table/td[contains(text(),"My Portal")]
2- The command that you are using it should work, I already tried, check your path again, maybe you are not selecting his parent or you are starting from the wrong path.
function xpath(){
var input = document.getElementById("xpath").value
var cell = document.evaluate( input, document, null, XPathResult.ANY_TYPE, null );
var cellvalue = cell.iterateNext();
console.log(cellvalue);
alert(cellvalue.data);
};
<html>
<head>
</head>
<body>
<input type="text" id="xpath" value='//body/table/tbody/tr/td/table//td[contains(text(),"My Value")]/text()'/> <input type="button" onclick="xpath()" value="Execute"/>
<table>
<tbody>
<tr>
<td>
<table>
<tbody>
<tr>
<td>
My Value
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>

Reading HTML Table Head value in Adobe DTM

I'm using Adobe DTM and I'm trying to get the value from a table (I have no control over this format or naming) and I'd like to grab the value of "Opened Account" in the example below but not sure how to go about it in DTM? I'm trying to target "th.rich-table-headercell" but not sure how to grab value?
<table class="rich-table home table" id="startForm:OpenedReviewApps" border="1" cellpadding="0" cellspacing="0">
<colgroup span="0"></colgroup>
<thead class="rich-table-thead">
<tr class="rich-table-header">
<th class="rich-table-headercell" scope="colgroup">Opened Accounts</th>
</tr>
</thead>
<tbody id="startForm:OpenedReviewApps:tb">
<tr class="rich-table-row rich-table-firstrow">
<td class="rich-table-cell" id="startForm:Open" style="width:80%">
some data here
</td>
</tr>
</tbody>
</table>
There may be a better way to do this, depending on what/when/where you are trying to get the value (e.g. page load rule vs. event based rule), but in general, based on your html, here is one way to do it.
Go to Rules > Data Elements, and click on Create New Data Element.
Name the Data Element something like "table_header" or whatever convention you currently use.
For Type, choose "CSS Selector".
For CSS Selector Chain, use "th.rich-table-headercell" (no quotes).
For get the value of, select "text".
(Optional, but recommended) Check the Scrub whitespace and linebreaks using cleanText option.
Now, for example, you can create a page load rule, and use %table_header% in your condition(s) or variable field(s). Or, if you need to reference it in javascript in a custom code box, use _satellite.getVar('table_header')

Why does this Javascript only run once per page?

I have this Try-it-Yourself section to my website but for some reason when I am wanting to have more than one Try-it-Yourself section it will only work for the one at the top of the page. So if I had three of them on a page the top one would work in the way I want but the next two would do nothing.
I have the following HTML:
<div class="tryit">
<table>
<tr>
<td>Try It Yourself</td>
</tr>
<tr>
<td><textarea id="input" rows="10" cols="47"></textarea></td>
</tr>
<tr>
<td><input onclick="update();" type="button" value="Update"></td>
</tr>
<tr>
<td><iframe id="output" name="output" width="600" height="300" ></iframe></td>
</tr>
</table>
</div>
And the following Javascript:
function update()
{
var tryitoutput = document.getElementById('input').value;
window.frames['output'].document.documentElement.innerHTML = tryitoutput;
}
Thank you.
As others mentioned, this is happening because there can't be more than one HTML element with same value of ID attribute. In your case javascript only finds the first element, that's why it doesn't work on later Update buttons. The simplest approach would be to set different ID attribute values for different "Try it yourself" boxes:
Slightly modify your JS, see following jsFiddle example
function update(tryItIndex) {
var tryItOutput = document.getElementById('input-' + tryItIndex).value;
window.frames['output-' + tryItIndex].document.documentElement.innerHTML = tryItOutput;
}
That's because you are referring to the textarea and the output by id which means it will always just retrieve the first one. A quick fix would be having unique id's for these fields and send the names as parameters to the update function like update(inputId, outputId)

Categories