Dynamic ID in Javascript - javascript

I am making something where I have dynamic ID for element i.e something like this in my index.ejs
<% for ( var i= 0; i<100; i++ ) { %>
<th> <span class="Pr" id=price"<%=i%>">$<%= result[i]["price"] %></span></th>
<%} %>
This should generate ID which increments with i for example price1, price2 and so on..
Now I am using Socket.io to obtain new data. After obtaining the new data, I want to change the innerHTML
Traditionally, I know I can do something like
document.getElementsByID("id").innerHTML = newData;
But I knew the ID there well in advance, Here the ID obtained is when the data obtained from socket.io matches my iTH element
document.getElementById('price' + i).innerHTML
I was hoping that this would make my ID as price0, price1, price2 (when i=0,1,2) but this doesn't seem to be working.
Please do let me know how I can fix this?

There appears to be quotes in your id attribute, which would produce ids like
id=price"0"
id=price"1"
id=price"2"
As you can see that is incorrect formatting. Change to:
id="price<%=i%>"
Which will produce the correctly formatted attributes:
id="price0"
id="price1"
id="price2"

I try dynamic ID using your code it is working fine.
You can see this
for (let i = 0; i < 4; i++) {
document.getElementById('price' + i).innerHTML ="test";
}
<span class="Pr" id="price0">price0</span>
<span class="Pr" id="price1">price1</span>
<span class="Pr" id="price2">price2</span>
<span class="Pr" id="price3">price3</span>

Related

rails selection quantity javascript get class not working index

What want to do:
I creating ec site by ROR. What I want to do is can select the quantity each items in checkout page(Specifically, make plus and minus button then select the quantity).
The variable are #items and #user_items_quantity and Im adding index number on it.
Then what I mean, getting the (div class) in Javascript which is had index number and I want to edit quantity and show it.
But impossible to get (div class with index) in js each items. I was thinking to roop "for" in js but I can't.
Can you tell me how I work out please?
_user_basket_items.html.erb
<% #items.zip(#user_items_quantity).each.with_index(1) do | (item, uiq), index | %>
 <div class="entry value-minus quantity-minus[#{index}]" id="value-minus"> </div>
 <div class="entry value score-value quantity-score[#{index}]" id="score-value"><%= uiq %></div>
 <div class="entry value-plus active quantity-plus[#{index}]" id="value-plus"> </div>
<% end %>
///
item_quantity.js
var add = document.getElementsByClassName( "quantity-plus" )["#{index}".to_i];
var remove = document.getElementsByClassName( "quantity-minus" )["#{index}".to_i];
var scoreValue = document.getElementsByClassName( "quantity-score" )["#{index}".to_i];
var int = 0;
add.addEventListener('click', function() {
int = parseInt(scoreValue.innerHTML, 10)+1;
scoreValue.innerHTML = int;
});
remove.addEventListener('click', function() {
int = parseInt(scoreValue.innerHTML, 10)-1;
scoreValue.innerHTML = int;
});
the css classes that you are generating looks like this:
<div class="entry value-minus quantity-minus[1]"
or
<div class="entry value-minus quantity-minus[2]"
but your javascript is looking for document.getElementsByClassName( "quantity-minus" ) with a mix of ruby syntax (["#{index}".to_i]) and js. Is your js template parsing ruby? You don't provide how index is initialized.
if it is, I would change the javascript as follows:
var add = document.getElementsByClassName( "quantity-minus[#{index.to_i}]" );
If your template isn't parsing ruby, you have to find another way.
As a side note, in your partial you are iterating over a list and giving static ids to the elements (id="value-minus") you should try avoid doing that

How to set the values from the json response to the <p> fields in php and javascript?

I am developing one web application where, there is one page, with the search bar, where one can search the projects by name. we'll get the list of projects or the desired project just below that search bar. Now when I click on the project name, I want to get the list of team members for that project to be visible just below that project details. I have the following code, I used 'post' call to call the backend and get the list of members for that project and get the result into JSON. Now I want to put these values to the <p> tags for that team member information. Following is the code:
In Index.php
<div id="members" class="list" style="display: none;">
<div class="result">
<div class="photo">
<img>
</div>
<div class="team_info">
<div class="tm">
<div class="member_name">
<h5>Member Name</h5>
<p id="member_name"></p>
</div>
<div class="prof">
<h5>profession</h5>
<p id="mem_profession"></p>
</div>
</div>
</div>
<div class="contact_button">
<h4 id="contact">See Contact</h4>
</div>
</div>
</div>
<script type="text/javascript">
$('#project_name').on("click",function(){
$.post('/teamMembers.php', {}, function(res){
for(var i=0; i < res.length; i++ ){
$('#member_name').val(res[i]['name']);
$('#mem_profession').val(res[i]['profession']);
}
$('#members').show();
});
});
</script>
In teamMembers.php Controller file
<?php
if(isset($_SESSION['project_name'])){
$project_name = $_SESSION['project_name'];
$members = \Model\Team_Member::getList(['where'=>"project_name = '$project_name'"]);
$this->toJson($members);
}
?>
I have stored the project name in $_SESSION and I get the response of these json request in the following manner:
[{
"name":"ABC",
"email":"test#test.com",
"phone":"9874563210",
"project_name":"Test Project",
"profession":"student",
"id":1312
}]
After all this code, I am still facing some issues like: I am not able to see the any of the team members details, not even the label, even though I use .show() function. Another I am not sure if that was the correct way to set the values to the <p> element from the json response. Help is appreciated
Paragraphs cannot have values, you need to set the text within them:
for(var i=0; i < res.length; i++ ){
$('#member_name').html(res[i]['name']);
$('#mem_profession').html(res[i]['profession']);
}
OR
for(var i=0; i < res.length; i++ ){
$('#member_name').text(res[i]['name']);
$('#mem_profession').text(res[i]['profession']);
}
If your markup repeats, you need to make sure each element has unique ID's. ID's Must Be Unique, specifically because it will cause problems in JavaScript and CSS when you try to interact with those elements.
EDIT: I tested with the following code. You do not need the for() loop (unless you're planning to expand this, at which point the unique ID's come into play):
// you do not need the first couple of lines of code, was just used for testing
var json = '[{"name":"ABC","email":"test#test.com","phone":"9874563210","project_name":"Test Project","profession":"student","id":1312}]';
var res = JSON.parse(json);
$('#member_name').html(res[0]['name']);
$('#mem_profession').html(res[0]['profession']);
$('#members').show();
EDIT 2: If you have more than one member of a project you can append their data to each paragraph like this:
var json = '[{"name":"ABC","email":"test#test.com","phone":"9874563210","project_name":"Test Project","profession":"student","id":1312},{"name":"XYZ","email":"test#test.com","phone":"9874563210","project_name":"Test Project","profession":"teacher","id":1312}]';
var res = JSON.parse(json);
for(var i = 0; i < res.length; i++) {
$('#member_name').append(res[i]['name'] + ', ');
$('#mem_profession').append(res[i]['profession'] + ', ');
}
This results in output like this:
Member Name
ABC, XYZ,
profession
student, teacher,

What's the best way to append an element using angular?

My objective is to show a grid of products and ads between them.
warehouse.query({limit: limit, skip: skip}).$promise
.then(function(data) {
for (var i = 0; i < data.length; i++) {
var auxDate = new Date(data[i].date);
data[i].date = auxDate.toISOString();
}
Array.prototype.push.apply($scope.products, data);
//add an img ad
var warehouseElem = angular.element(document.getElementsByClassName('warehouse')[0]);
var newAd = $sce.trustAsHtml('<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>');
warehouseElem.append(newAd);
skip += 9
});
Doesn't work.
I already tried simply using pure javascript like,
var warehouseElem = document.getElementsByClassName('warehouse')[0];
var newAd = document.createElement('img');
warehouseElem.appendChild(newAd);
Also doesn't work.
I suppose I need to do something with angular, can't find out what. I think it's sanitize but maybe I just don't know how to use it.
Remember I need to inject an img every once in a while between products.
This is a job for ng-repeat!
<div ng-repeat="data in datas">
<div>[show data here]</div>
<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>
If you have bind your "datas" in scope and Math too like this in your controller like this it should works
$scope.datas // this is your list of products
$scope.Math = Math;
If you don't want to spam add for each line you can use ng-if with $index like this :
<div ng-if="$index%2==0">
<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>
This will make it display add every 2 lines.
Since you seemed to come from a jQuery-like (or native DOM manipulation) background, I suggest you to read that post : "Thinking in AngularJS" if I have a jQuery background?.
This will explain you why in angular you almost don't manipulate DOM and quite some other things (only in directives).
EDIT : to fix the grid problem, just merging my two html block build your array of datas like this :
$scope.myArray = [product[0], ad[0] or just an empty string it will work still, product[1], ad[1]]
And the html
<div ng-repeat="data in datas">
<div ng-if="$index%2==0">[show data here]</div>
<img ng-if="$index%2==1 src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>
</div>
In AngularJS you should generally avoid doing DOM manipulation directly and rather rely on angular directives like ng-show/ng-hide and ng-if to dynamically hide sections of a template according to the specific case.
Now back to the problem at hand.
Assuming that you are trying to render a list of products loaded with the code displayed above and display an ad for some of them, you can try the following.
<!-- place the img element in your template instead of appending -->
<div ng-repeat="product in products">
<!-- complex product template-->
<!-- use ng-if to control which products should have an ad -->
<img ng-src="product.adUrl" ng-if="product.adUrl" />
</div>
Then in your controller set adUrl for products that should have an ad displayed.
warehouse.query({limit: limit, skip: skip}).$promise
.then(function(data) {
for (var i = 0; i < data.length; i++) {
var hasAd = // set to true if this product should have an add or not
var auxDate = new Date(data[i].date);
data[i].date = auxDate.toISOString();
if(hasAd){
data.adUrl = "/ad/?r=" + Math.floor(Math.random()*1000);
}
}
Array.prototype.push.apply($scope.products, data);
skip += 9
});
I am most probably assuming too much. If that is the case please provide more details for your specific case.
If you declare a scope variable,
$scope.newAd = $sce.trustAsHtml('<img src="/ad/?r=' + Math.floor(Math.random()*1000) + '"/>');
and in your HTML template, have a binding like
<div ng-bind-html="newAd"></div>,
it should work.

Get innerHTML from same tags

I am having a trouble for fetching innerHTML of the following two strong tags
<div>
<strong>data 1</strong>
<span class="and">and</span>
<strong>data 2 </strong>
</div>
<div>
<strong>data 3</strong>
<span class="and">and</span>
<strong>data 4 </strong>
</div>
i want to get data1, data2 in console but i'm unable to achieve anything.
I have tried document.querySelector("strong") but it just provide me data1.
How can i fetch data2 data3 & data4 from other strong tag?
Any help is appreciated.
i know i can do
document.getElementsByTagName("strong")['increment_operator'].innerHTML;
and
document.querySelectorAll("strong");
querySelector finds the first result and stop searching whereas querySelectorAll finds all.
Try code below to log html of strong tag:
var elems = document.getElementsByTagName('strong');
for (i=0;i < elems.length;i++{
console.log(elems[i].innerHTML)
}
To get innerHTML of the last strong tag in html run code below:
var elems = document.getElementsByTagName('strong')[:1];
console.log(elems[elems.length-1].innerHTML);
If you have same tag and you want specific tag innerHTML then give unique ids and then try to fetch or if you want to fetch all strong tag innerhtml then use queryselectorall()
As example
<div>
<strong>data 1</strong>
<span class="and">and</span>
<strong>data 2 </strong>
</div>
<div>
<strong>data 3</strong>
<span class="and">and</span>
<strong>data 4 </strong>
</div>
var a = document.querySelectorAll("strong");
for (var i = 0; i < a.length; i++) {
alert(a[i].innerHTML);
}
Summing up the partials:
The document.querySelector(commaSeperatedStringOfSelectors) only finds the first node in the documentsatisfying the selectors it is given. So you need to be more specific with it, need to supply some queryable selectors to your html elements, like id class.
But if you want to select more widely follow:
document.querySelectorAll(commaSeperatedStringOfSelectors) to get an array of all the nodes satisfying the selectors. Then you can select the element you need by index. fiddle
Or you need to use #Andriy Ivaneyko's answer style, use getElementByTagName('tagname'), getElementsByClassName('class'), or getElementById('id').
Note: document.querySelectorAll(commaSeperatedStringOfSelectors) is more versatile, it gives you opportunity to be both more specific or more unspecific. You can use a string like that in it: 'strong, div.animals, a'.
Ok i did my job by doing following.
var divLength = document.getElementsByTagName("div").length;
var z = 0;
for(i=0; i<divLength; i++){
var dataFromFirstStrong = document.getElementsByTagName("strong")[z].innerHTML;
z++;
var dataFromSecondStrong = document.getElementsByTagName("strong")[z].innerHTML;
z++;
}

For Loop in MVC 4 From JavaScript value

How can I make a repeater type in the page. In the page I have a quantity field:
<td>
#Html.DisplayNameFor(x => x.Quantity)
#Html.ValidationMessageFor(x => x.Quantity)
</td>
<td>
#Html.TextBoxFor(x => x.Quantity, new { #id = "txtQty" })
</td>
When I want to add the item, which there could be several of the same item, just different serial numbers, I need to pop open a div with repeated fields for entering serial numbers:
for (int I = 0; I < *****; I++)
{
<td>Serial Number:</td>
<td>#Html.TextboxFor(x=>x.Quantity, new { #id = "txtQty" + 1})
}
In the JS:
function AddItem() {
Qtys = parseINT($("#txtQty").val());
$("#divSerials").show();
}
How can I do this? Is there a better way?
Is this the way to do it? I try this but 'i' in the HTML model statement is not recognized.
if (parseInt($("#txtQuantity").val()) > 0) {
$("#divSerialNumbers").show();
var html = "<table>";
for (i = 1; i <= serialquantity; i++) {
html += "<tr><td>Serial Number:" + #Html.TextAreaFor(x => x.SerialNumber, new { id = "sns" + i }) + "</td></tr>";
}
html += "</table>";
$("#divSerialNumbers").html(html);
}
Razor code is parsed on the server before it is sent to the view. Javascript is client side code and is not executed until the browser receives the view. This line of code
#Html.TextAreaFor(x => x.SerialNumber, new { id = "sns" + i })
means that on the server you are trying to generate a textarea and set the id attribute to a value that includes a javascript variable which does not yet exist.
Its unclear even what the point of this would be. id attributes serve as selectors in javascript. Whats important is the name and value attributes when it comes to posting your data, and even if it could work, your generating duplicate name attributes which could not bind to you models collection property on post back.
For dynamically generating the html for collections, your name attributes need an indexer, for example <input type="text" name="[0].SerialNumber" />. Options for dynamically creating the html include using the BeginCollectionitem() helper, or a pure client side approach is shown in this answer
If all you are doing is post back an array of strings (the serial numbers) then you could use
var div = $("#divSerialNumbers"); // cache it
$('#Quantity').change(function() { // assumes you remove the pointless 'new { #id = "txtQty" }'
var quantity = parseInt($(this).val()); // use $(this) - don't traverse the DOM all over again
if (!isNan(quantity) && quantity > 0) { // must check for NAN
// note it does not seem necessary to use a table, as opposed to simply adding 4 inputs to the div, but
div.empty(); // clear existing contents
var table = $('</table>');
for (i = 1; i <= quantity; i++) {
var input = $('<input>').attr('name', 'SerialNumber');
var cell = $('</td>').append(input);
var row = $('</tr>').append(cell);
table.append(row);
}
div.append(table).show(); // add the table and display it
}
})
and your controller would need a parameter string[] SerialNumber, for example
public ActionResult Edit(string[] SerialNumber)

Categories