Dynamically create an element with an event handler that takes a string - javascript

This is driving me insane.
I create a cell in a table dynamically through:
tr.append("<td>" + countryArr[i].ISO_id + "</td>");
I created a button that when clicked calls a function with the value countryArr[i].ISO_id. This value is a string and needs to be called in "quotes".
I cannot get the function to be called with quotes.
I've tried:
tr.append("<td><button type='button' onclick='showCyclists(" + cId + ")'>Show country's cyclists</button></td>");
tr.append("<td><button type='button' onclick='showCyclists("" + cId + "")'>Show country's cyclists</button></td>");
tr.append("<td><button type='button' onclick='showCyclists('" + cId + "')'>Show country's cyclists</button></td>");
None of these work. Please help

With ES6 you you could just use the following called template literals, note the backticks `
tr.append(`<td><button type='button' onclick='showCyclists("${cId}")'>Show country's cyclists</button></td>`);

Just add escaped quotes showCyclists(\"" + cId + "\"):
tr.append("<td><button type='button' onclick='showCyclists(\"" + cId + "\")'>Show country's cyclists</button></td>");

You can't use single quotes because those are being used to delineate the attribute. You could use escaped double quotes to get this to work:
tr.append("<td><button type='button' onclick='showCyclists(\"" +
cId +
"\")'>Show country's cyclists</button></td>");
However, while it is possible to get your approach to work by manipulating the strings, the solution you are trying to use here (inline event handlers, and furthermore, inline event handlers created from JavaScript strings) is a bad practice.
Save yourself some headaches and build up the elements properly. Your code might be a few lines longer, but it will be cleaner.
Good approach:
var button = $('<button type="button">')
.text("Show country's cyclists")
.on('click', function () { showCyclists(cId) });
var td = $('<td>').append(button);
tr.append(td);
Working example:
function showCyclists(id) {
console.log("Here are all the cyclists.");
console.log(id);
}
var tr = $('tr');
var cId = '12345';
var button = $('<button type="button">')
.text("Show country's cyclists")
.on('click', function() { showCyclists(cId); });
var td = $('<td>').append(button);
tr.append(td);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr></tr>
</table>

Related

Using data from API inside javascript

i am using northwind api. Some products i get from api have ' in their name and its a problem because i wanna use it inside of function... I wanna have function buy that sends cost, name of product and quantity per unit, but when I call function i get inside of html
Instead of
<button onclick='buy(4,"Chef Anton's Cajun Seasoning",22.0000)'>Buy</button>
I tried using single quotes, double quotes, switched between, tried with \' and \" and different variation of ' and " , but nothing seams to work... Here is part of line of code that is troubling me
<button onclick ='buy(" + products.value[j].ProductID + ",'"
+ (products.value[j].ProductName)+"',"+ products.value.UnitPrice +")'>Buy</button></div></div>"
also Northwind api I am usin is
https://services.odata.org/V3/Northwind/Northwind.svc/Products?$format=json
You could use HTML5 data-* custom attribute to pass arbitrary data to event handler.
'<button data-product-id="' + products.value[j].ProductID '+" data-product-name="' + products.value[j].ProductName'+" data-unit-price="' + products.value.UnitPrice'+" onclick="wrapperBuy(this)">Buy</button>'
which can later, be fetched using Element.dataset property
function wrapperBuy(element) {
var productId = element.dataset.productId,
productName = element.dataset.productName,
unitPrice = element.dataset.unitPrice;
console.log(productId, productName, unitPrice);
//You can invoke the original buy method
//buy(productId, productName, unitPrice)
}
<button data-product-id="4" data-product-name="Chef Anton's Cajun Seasoning" data-unit-price="2200" onclick="wrapperBuy(this)">Buy</button>
Additionally, I would strong recommend you to use unobtrusive event handlers i.e. addEventListener()
Try this
<button onclick ="buy(\'' + products.value[j].ProductID + '\',\'' + (products.value[j].ProductName) + '\',\'' + products.value.UnitPrice + '\')">Buy</button>

How can I reuse result from JQuery for javascript textual matching?

I have html elements coming into function as string, then I am injecting elements into it as string however to my surprise it didn't work.
something like:
var replacement = $(row).find('td:last').append("<script type=\"text/javascript\"> function remove" + override.SessionKey + "(){ $('tr[session-key=\"" + override.SessionKey + "\"]').remove(); }</script><input type=\"button\" value = \"Remove\" onClick=\"remove" + override.SessionKey + "()\" />")
row.replace($(row).find('td:last')[0],replacement[0])
After some further investigation I have narrowed it down to matching failing in replace function, basically after you search with JQuery result cannot be used for textual matching
Here is an example of what I mean:
var r = "<tr class=\"hide\" session-key=\"SessionProductDataMotorEnrichmentSagaFactorScore\" session-key-data-type=\"Decimal\"><td id=\"tdDisplayName91\">SagaFactorScore</td><td id=\"tdValue91\"></td></tr>"
$('div').text(r.indexOf($(r).find('td:last')[0]));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div></div>
One would expect to always have a match as I am using contents of original html string.
How can I reuse result from JQuery for textual matching?
I think you're looking for .outerHTML:
var r = "<tr class=\"hide\" session-key=\"SessionProductDataMotorEnrichmentSagaFactorScore\" session-key-data-type=\"Decimal\"><td id=\"tdDisplayName91\">SagaFactorScore</td><td id=\"tdValue91\"></td></tr>"
$('div').text(r.indexOf($(r).find('td:last')[0].outerHTML));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div></div>
That is a terrible way of doing what you're trying to do.
var btn = $("<button></button>");
btn.attr("type","button").text("Remove").on("click",function() {
var tr = $(this).closest("tr");
tr.remove();
});
This creates the button with associated event bound directly to it. You can then append it to all rows, for instance, like so:
$("tr>td:last-child").append(function() {return btn.clone(true);});

jQuery: trying hook a function to the onclick when page loads

I have seen a similar question, HERE and have tried that, but I can't seem to get it working.
Here is my code for dynamically generating table rows.
for (var contribution = 0; contribution < candidate.contributions.length - 1; contribution++) {
var id = candidate.contributions[contribution].donor_id;
var uid = candidate.contributions[contribution].user_id;
$("#history-table").append(
"<tr onclick='" + parent.viewEngine.pageChange('public-profile', 1, id, uid) + ";>" +
"<td class='img-cell'>" +
"<img class='profile-avatar-small' src='/uploads/profile-pictures/" +
candidate.contributions[contribution].image + "' alt='' /></td><td class=''>" +
"<h2>" + candidate.contributions[contribution].firstname +
" " + candidate.contributions[contribution].lastname + "</h2></a><br/><br/>" +
"<span class='contribution-description'>" + candidate.contributions[contribution].contribution_description + "</span></td>" +
"<td><h3>$" + formatCurrency(candidate.contributions[contribution].contribution_amount) + "</h3></td></tr>");
}
This still executes the click event as soon as the page loads, which is not the desired behavior. I need to be able to click the tr to execute the click event.
Pass the whole thing as a string:
"<tr onclick='parent.viewEngine.pageChange(\'public-profile\', 1, " + id + ", " + uid + ");>" // + (...)
But, as you are using jQuery, you should be attaching the click handler with .on().
(I really don't recommend using inline event handlers like that, especially when you're already using jQuery, but anyway...)
The problem is that you need the name of the function to end up in the string that you are passing to .append(), but you are simply calling the function and appending the result. Try this:
...
"<tr onclick='parent.viewEngine.pageChange(\"public-profile\", 1, " + id + "," + uid + ");'>" +
...
This creates a string that includes the name of the function and the first couple of parameters, but then adds the values of the id and uid variables from the current loop iteration such that the full string includes the appropriately formatted function name and parameters.
Note that the quotation marks around "public-profile" were single quotes but that wouldn't work because you've also used single quotes for your onclick='...', so you should use double-quotes but they need to be escaped because the entire string is in double-quotes.
I'm wondering if you might be better simplifying things a bit.
If your rows are being dynamically added, then try putting some kind of meta-data in the <tr> tag, e.g. something like this:
<tr id="id" name="uid">
Then try the following with your jQuery (v.1.7 required):
$('#history-table tr').on('click', function(){
parent.viewEngine.pageChange('public-profile', 1, this.id, this.name);
});
This will likely require modification depending on how your page rendering works but it's a lot cleaner and easier to read having been removed from your main table markup.
Well that's because you're executing the function, not concatenating it. Try:
onclick='parent.viewEngine.pageChange("public-profile", 1, id, uid);'
Take this ->
$("#contribution-" + uid).click(function(){
parent.viewEngine.pageChange('public-profile',1, id, uid);
});
And do two things:
1) Move it outside of the 'for' statement
As soon as the for statement is executed, the click function will be executed as well. The click function is not being supplied as a callback function in this for statement.
2) Change it to ->
$("tr[id^='contribution-'").on('click', function(){
var idString = $(this).attr("id").split("-"); //split the ID string on every hyphen
var uid = idString[1]; //our UID sits on the otherside of the hyphen, so we use [1] to selec it
//our UID will now be what we need. we also apply our click function to every anchor element that has an id beginning with 'contribution-'. should do the trick.
parent.viewEngine.pageChange('public-profile',1, id, uid);
});
This is my solution.

Variable within quote within quote?

Im trying to use inner html and dynamically set an onclick statement that contains a variable:
cell5.innerHTML="<input type='button' value='Remove' onclick='removerow('manual_" + (num) + "')' />"
So lets say the num variable was set to 4. The output should be onclick="removerow('manual_4')"
Any help?
The best thing would be to avoid all this:
var input = document.createElement('input');
input.type = 'button';
input.value = 'Remove';
input.onclick = function() {
removerow('manual_' + num);
};
cell5.appendChild(input);
Depending on the relationship between the button, the cell and the row to be removed, you could also do DOM traversal inside the handler to get a reference to the row.
You can escaped nested quotes using \:
"...onclick=\"removerow('manual_" + (num) + "')\"..."
cell5.innerHTML='<input type="button" value="Remove" onclick="removerow(\'manual_' + (num) + '\')" />'
You can escape the quotes using \
So
onclick=\"removerow('manual_" + (num) + "')\"
Consider using a click event instead. It makes that sort of thing clearer:
$(".cell5") // whatever selector you want
.html('<input type="button" value="Remove"/>')
.click(function(){
removerow('manual_' + row);
});
Also consider using the row number as the input instead of a string. If they all have the same form you can simplify things with just:
removerow(row);
Clearly that is an API design decision, but it would simplify this expression if it makes sense.

jQuery/JavaScript: Avoid unique ID's for each row in a table?

I'm not sure if I'm doing this the right way. I have table which I fill with rows that each represent a song in a playlist. Right now, I assign a unique ID per row, and also assign som jQuery.data() to each ID.
html += '\
<tr id="track-' + i + '" class="tracks-row"> \
<td class="track"><a id="play-'+ i +'" class="play"></a><a id="play2-' + i + '">' + song.song_track + '<span class="mix-style">' + song_mix + '</span></a></td> \
<td class="artist">' + song.song_artist + '</td> \
<td class="favourites-holder"><a id="favourite-' + i + '" class="favourites"></a></td> \
' + delete_holder + ' \
</tr> \
';
So as you can see, each row has an ID like track-1, track-2 etc.
Is there another way to populate a playlist like this without assigning unique ID's to each track, or is this how it's supposed to be done? Each track has some properties like this:
$("#track-" + i).data("song_id", song.song_id);
$("#track-" + i).data("song_artist", song.song_artist);
$("#track-" + i).data("song_track", song.song_track);
$("#track-" + i).data("song_mix", song.song_mix);
$("#track-" + i).data("ps_id", song.ps_id);
... and also .click events for each track, which allows the user to play, sort, drag etc... It just feels like I'm doing it wrong :)?
You could store a reference to each generated row in your loop (assuming html only contains the HTML for a single row):
var row = $(html).appendTo("#table");
var data = row.data();
data["song_id"] = song.song_id;
data["song_artist"] = song.song_artist;
data["song_track"] = song.song_track;
data["song_mix"] = song.song_mix;
data["ps_id"] = song.ps_id;
row.click(function(){...});
It is not bad to have an ID for an element. But is definitely faster to make use of a reference if you have one and not use jQuery's selector engine over and over again.
Also if you attach the same click handler to every row, it is probably better to just attach one to the table and delegate it, e.g.
$('#table').delegate('tr', 'click', function(){...});
Unique id's makes sense or use the Metadata plugin to store all the extra data related to each row. http://plugins.jquery.com/project/metadata
It will store the data like:
<li class='someclass' data="{some:'random', json: 'data'}">...</li>
And you can query this like this:
var data = $('li.someclass').metadata();
if ( data.some && data.some == 'data' )
alert('It Worked!');
Whether the tr needs a unique id or simply a generic class is going to depend a lot on what you intend to do with either javascript (for targeting the rows) or css (also for targeting the rows). If you need to specifically target one row for styling or script effects, a unique id can be an effective way of doing it. If not, then it may be extra "mark-up" that is unnecessary.
In any case, if you do use id's, do make sure they are unique :-)
May be something like this with jquery:
var songs = function(songList){
this.songs = songlist;
this.init();
}
$.extend(songs.prototype, {
init: function(){
var self = this;
var table = $('#myTableID');
for(var i = 0; i < this.songs.length; i++){
var song = this.songs[i];
var songData = $('<tr><td class="track">'+song.track+'</td><td class="artist">'+song.artist + '</td></tr>');
table.append(songData);
songData.find('td.track:first')click(function){
self.SongClick(song.track);
});
//add other events here
}
}
},
SongClick : function(track){
//add here you click event
},
otherEvent : function(track){
//add otherEvent code
}
});
Like this you can create your javascript object and attach events to the dom elements directly as you parse them. You will not need any id's.
This approach will create a js object with its constructor
so you can say
var so = new songs(mySongList)
when it initializes it will retrieve a table with an id of myTableID and foreach song in the list, it will attach elements to it, and will attach the events directly to those elements.

Categories

Resources