Using data from API inside javascript - 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>

Related

How do i use onclick() method properly when passing some variable arguements i.e the arguements in this case is an ID of a Mongoose Object Document?

So I'm dynamically appending rows to a table on front-end, based on the array I get from a node.js API I wrote. The array indicates students. For each row I append and display Name, Class, Roll_No and a dynamic button whose color changes depending on the value I get from that specific student. Now for that button I use the following tag:
$('#users').append("<tr><td>" + (i + 1) + "</td><td>" + val.first_name + " " + val.last_name + "</td><td>" + val.roll_no + "</td><td>" + val.class + "</td><td><button id='tempButton' class='btn btn-danger' onclick='add_remove_student(" + val._id + ", " + val.is_linked + ")'>DELETE</button></td></tr>");
val indicates the current element of the students array, which is a mongoose object. Now I get an error whenever I click the appended button and the add_remove_student() method is not called. The error says:
uncaught SyntaxError: Invalid or unexpected token
val._id is a Mongoose ID of that particular Mongoose object and val.is_linked is a boolean value.
The onclick() in the button tag worked before I switched to node.js
I've scratched my head so many times as to what I'm doing wrong. Any help would be greatly appreciated!
The short answer: don't use onclick, or any other of the onX inline event attributes. They are outdated, lead to spaghetti code and don't follow the separation of concerns principle.
A much better way to achieve this would be to just add the relevant meta data to the element as data attributes. Then, using a single delegated event handler, you can read that metadata from the element which was clicked. Try this:
let i = 0;
let val = {
_id: "5e4780d3cfbe57182499506a",
role: ["STUDENT"],
is_active: true,
linked_students: [],
first_name: "test_fname",
last_name: "test_lname",
email: "t1#t.com",
roll_no: "537",
class: 7,
description: "im a test user mate!",
created_at: "2020-02-15T05:25:39.077Z",
updatedAt: "2020-02-15T05:25:39.077Z",
v: 0,
is_linked: true
}
$('button').on('click', function() {
$('#users').append(`<tr><td>${(++i)}</td><td>${val.first_name} ${val.last_name}</td><td>${val.roll_no}</td><td>${val.class}</td><td><button class="delete btn btn-danger" data-id="${val._id}" data-linked="${val.is_linked}">DELETE</button></td></tr>`);
});
$('#users').on('click', '.delete', function() {
let $btn = $(this);
let id = $btn.data('id');
let isLinked = $btn.data('linked');
console.log(id, isLinked);
// do something with the above data...
$(this).closest('tr').remove();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Append</button>
<table id="users"></table>
As a side note, don't use id attributes in content which will be dynamically repeated. id need to be unique in the DOM. Use class attributes instead.
If, for whatever reason, you absolutely had to use an inline event attribute you need to fix your quotes so that they match, and you also need to escape the quotes you use in the onclick value so they don't interfere with the outer string:
$('#users').append('<tr><td>' + (i + 1) + '</td><td>' + val.first_name + ' ' + val.last_name + '</td><td>' + val.roll_no + '</td><td>' + val.class + '</td><td><button id="tempButton" class="btn btn-danger" onclick="add_remove_student(\"' + val._id + '\", \"' + val.is_linked + '\")">DELETE</button></td></tr>');
Okay so I've wrecked my brain for 24 hrs to solve this and after understanding how escape quotes characters work i've finally solved it with the following code:
$('#users').append(`<tr><td>` + (i + 1) + `</td><td>` + val.first_name + ` ` + val.last_name + `</td><td>` + val.roll_no + `</td><td>` + val.class + `</td><td><button id="tempButton" class="btn btn-danger" onclick='add_remove_student(\"` + val._id + `\",\"` + val.is_linked + `\")'>DELETE</button></td><tr>`);
Thank You ^^
This is the issue of mixing of quotes please re verify the quotes on the function calling in jquery. Plus please made an id of the element dynamic.

How to pass a value from a Javascript generated button to a controller?

My code generates a table with a button at the end of each row. When the user clicks a button how can I pass a property u.userEmail to the controller via the button? Will the value being sent to the controller be a string?
My (non-working) attempt:
<script>
$(document.body).append("waiting on async table to load<br>");
$(document).ready(function () {
$.getJSON("/Account/LoadClaimsTable", function (crewResponse) {
//returns a List<UserClaims>
$(document.body).append("<table>")
crewResponse.forEach(function (u) {
var s = "";
s+="<tr><td>" + u.userEmail + "</td>";
u.userClaims.forEach(function (k) {
console.log("added claim"+k.value);
s += ("<td>" + k.type + "</td><td>" + k.value + "</td><td>" +
"<input type=\"hidden\" name=\"userEmail\" value=\"`${u.userEmail}`\" />"+
"<input type=\"button\" value=\"Create\" onclick=\"location.href='#Url.Action("EditClaims", "Account")'" />
+"</td>");
});
s += "</tr>";
$(document.body).append(s);
s = "";
});
$(document.body).append("</table>")
});
});
</script>
AccountController.cs contains:
public ActionResult EditClaims(string userEmail)
{
return View("StringView", userEmail);
}
You have to pass it on the url of the action. Not sure if you want to pass u.userEmail, but it could looks like this:
crewResponse.forEach(function (u) {
var s = "<tr><td>" + u.userEmail + "</td>";
u.userClaims.forEach(function (k) {
console.log("added claim"+k.value);
s += ("<td>" + k.type + "</td><td>" + k.value + "</td><td>" +
"<input type=\"hidden\" name=\"userEmail\" value=\"`${u.userEmail}`\" />"+
"<input type=\"button\" value=\"Create\" onclick=\"location.href='#Url.Action("EditClaims", "Account")?userEmail=" + u.userEmail + "'\"/></td>");
});
s += "</tr>";
$(document.body).append(s);
});
There are multiple ways to do it. One is mentioned in the answer above by Felipe. Here is another alternate approach using unobtrusive js
Add the email as html5 data attributes to the button along with another attribute which we will use bind the click behavior.
u.userClaims.forEach(function (k) {
// Add quotes as needed if you want multiline ( i just removed those)
s += "<td>" + k.type + "</td><td>" + k.value + "</td><td>
<input type='button'
clickablebutton data-email='" + u.email + "' value='Create'/></td>";
});
Now, in your document ready, bind a click event handler to those elements (with our custom attribute) and read the data attribute and build the url you need.
$(document).on("click", "input[clickablebutton]", function (e){
var url = '#Url.Action("EditClaims", "Accounts")?useremail=' + $(this).data("email");
window.location.href = url;
});
Some other suggestions
Use the appropriate element. Button is better than input (Consider accessibility)
If it is for navigation, Use an anchor tag instead of a button.
Inline javascript is not great. Let the browser parses your markup without any interruptions and you can add the behavior scripts later (that is the whole point of uobutrisive js approach)
The approach you appear to be taking would be Ajax, response, render a template. With that being said, you may want to rethink your approach.
Step 1.
Build a template
<template id="...">
<button type="button" value="[action]" onclick="[url]">[text]</button>
</template>
Step 2.
Create your request.
axios.get('...').then((response) => {
// Retrieve template.
// Replace bracket with response object model data.
html += template.replace('[action]', response.action);
});
Step 3.
Have the JavaScript render your template.
The above can create a clear concise codebase that is easier to maintain and scale as the scope changes, rather than an individual request performing a change with embedded markup. This approach has worked quite well for me, also I feel it'll make you troubleshooting and definition easier, as the controller is handing an object back to your JavaScript instead of a markup / view data. Which will be a better finite control for the frontend and clear modifications in future.

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

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>

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.

Categories

Resources