Add data to self created HTML object - javascript

Is there a reason this doesn't work ?
var link = $('Kies');
link.data('name', address.name);
link.data('street', address.street);
link.data('number', address.nr);
link.data('zip', address.zip);
link.data('city', address.city);
var message = $('<div style="min-width:150px;"><address><strong>' + address.name + '</strong><br>' + address.street + ' ' + address.nr + '<br>' + address.zip + ' ' + address.city + '</address>' + String(link) + '</div>');
returns:
<div style="min-width:150px;" class="">
<address>
<strong>John</strong><br>
Street 81<br>
Doe Doe
</address>
[object Object]
</div>
the address parameters are filled with normal strings so there is no problem there.

If you're expecting that attributes will be added by that code, that's not what data does. data never writes to data-* attributes, it just uses them for initialization. After initialization, there is no connection between the data managed by data and data-* attributes.
If you want attributes, use link.attr("data-name", address.name) and such instead.
But if you're just worried that you're not seeing the data on the element when you inspect it, but you're happy using data, your code does work. jQuery manages the data cache in a way that isn't shown in the DOM inspector. Example:
var address = {name: "address name"};
var link = $('Kies');
link.data('name', address.name);
display(link.data('name')); // "address name"
function display(msg) {
$("<p>").html(String(msg)).appendTo(document.body);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

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.

Appending HTML+RDFa with JavaScript

My JavaScript script is not allowing to be marked up semantically. As you can see in my script below, I am using Schema.org and RDFa.
The problem is that when I validate my page, only the part before the append function is validated. This means that only type, headline, publisher and datePublished comes up.
How can I fix it? I suspect the problem here is the append function.
$(document).ready(function(){
$.getJSON(webhose_request, function(results){ //send request to API and store results in "results"
//parse the results' from the JSON response and display them //in a div element for example <div class='webhoseapi'></div>
//we can loop to display all results in a for loop or using the results.posts.lenght; or just display a few.
for (var i = 0; i < 10; i++) {
// you need to read the JSON results to know how to parse them, for example here results.posts[i].text
var articletext = results.posts[i].text;
// we use regular expressions REGEX to replace any new line '\n' and carriage return '\r' with html breaks </br>
articletext = articletext.replace(/(?:\r\n|\r|\n)/g, '</br>');
$(".webhose").append('<div vocab="http://schema.org/" typeOf="Article"><div property="headline" class="whtitel">'+results.posts[i].thread.title_full.substring(0,110)+'</div><div class="source"><b>Source:</b><span property="publisher"> '+results.posts[i].thread.site+'</span></div></div>');
if(results.posts[i].thread.author){
$(".webhose").append('<div class="whpublished"><b>By:</b> <span property ="author">'+results.posts[i].thread.author+'</span></div>');
}
$(".webhose").append('<div class="whpublished"><b>Date published:</b><em><span property="datePublished"> '+results.posts[i].thread.published.substring(0,10)+'</p></span></em> </div>');
//we check if there is an image for this posts then display
if(results.posts[i].thread.main_image){
$(".webhose").append('<div class="whimage"><img property="image" src="'+results.posts[i].thread.main_image+'" height="125" width="200"/></div>');
}
$(".webhose").append('<div property="articleBody" class="wharttext">'+articletext.substr(0,500)+'... <div class="whlink"><a property="url" href= '+results.posts[i].thread.url+'> Read full article »</a></div></div><br>');
}
});
});
I think the issue is that most of the parts of the article aren't in the <div vocab="http://schema.org/" typeOf="Article"> element. This can be shown to be true if one indents HTML from the first append:
<div vocab="http://schema.org/" typeOf="Article">
<div property="headline" class="whtitel">'+results.posts[i].thread.title_full.substring(0,110)+'</div>
<div class="source"><b>Source:</b><span property="publisher"> '+results.posts[i].thread.site+'</span></div>
</div>
In the following I have changed the code to create the article div and then append the contents to it and then append it to the document. The following is untested but I think it might work.
$(document).ready(function() {
$.getJSON(webhose_request, function(results) { //send request to API and store results in "results"
//parse the results' from the JSON response and display them //in a div element for example <div class='webhoseapi'></div>
//we can loop to display all results in a for loop or using the results.posts.lenght; or just display a few.
for (var i = 0; i < 10; i++) {
// you need to read the JSON results to know how to parse them, for example here results.posts[i].text
var articletext = results.posts[i].text;
// we use regular expressions REGEX to replace any new line '\n' and carriage return '\r' with html breaks </br>
articletext = articletext.replace(/(?:\r\n|\r|\n)/g, '</br>');
var article = $('<div vocab="http://schema.org/" typeOf="Article"></div>');
article.append('<div property="headline" class="whtitel">' + results.posts[i].thread.title_full.substring(0, 110) + '</div>')
article.append('<div class="source"><b>Source:</b><span property="publisher"> ' + results.posts[i].thread.site + '</span></div>');)
if (results.posts[i].thread.author) {
article.append('<div class="whpublished"><b>By:</b> <span property ="author">' + results.posts[i].thread.author + '</span></div>');
}
article.append('<div class="whpublished"><b>Date published:</b><em><span property="datePublished"> ' + results.posts[i].thread.published.substring(0, 10) + '</p></span></em> </div>');
//we check if there is an image for this posts then display
if (results.posts[i].thread.main_image) {
article.append('<div class="whimage"><img property="image" src="' + results.posts[i].thread.main_image + '" height="125" width="200"/></div>');
}
article.append('<div property="articleBody" class="wharttext">' + articletext.substr(0, 500) + '... <div class="whlink"><a property="url" href= ' + results.posts[i].thread.url + '> Read full article »</a></div></div><br>');
$(".webhose").append(article);
}
});
});

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.

Displaying json data as a list in jQuery mobile

I am trying to retrieve a list of Staff entities from my datastore, and then display this as a list in my jQuery mobile app.
When i test this locally from my browser, it displays the data just fine like this:
[{"ID": "67", "Name": "Stevie Gerrad"},{"ID": "100", "Name": "Christiano Ronaldo"}]
But when i try it from my jQuery mobile app, nothing happens.Although there isn't any error and i get the status code:
Status Code: HTTP/1.1 200 OK.
In my Python code, i have:
class Staff(ndb.Model):
staff_id=ndb.IntegerProperty(required=True)
staff_name=ndb.StringProperty(required=True)
def asJSONString(self):
return '{"ID": "%s", "Name": "%s"}' % (self.staff_id, self.staff_name)
def toTableRow(self):
return "<tr><td>" + self.staff_id + "</td><td>" + self.staff_name + "</td></tr>"
class StaffHandler(webapp2.RequestHandler):
def get(self):
staff_id=self.request.get('id')
callback=self.request.get('callback')
staff=Staff.get_by_id(staff_id)
if staff:
self.response.write("A member with this id already exists")
else:
s_id = int(self.request.get('id'))
s_name= self.request.get('name')
staff=Staff(id=s_id, staff_id=s_id, staff_name=s_name)
staff.put()
if callback:
self.response.write(callback + '(' + staff.toJSON() + ')')
else:
self.response.write(staff.toJSON())
def getStaffList(callback):
members_of_staff = Staff.query()
strList=""
for staff in members_of_staff:
if len(strList) > 0:
strList+= ',' + staff.asJSONString()
else:
strList=staff.asJSONString()
if callback=='':
return '[' + strList + ']'
else:
return callback+ '([' + strList + ']);'
class StaffViewHandler(webapp2.RequestHandler):
def get(self):
callback=self.request.get('callback')
self.response.headers["Content-Type"] = "application/json"
self.response.out.write(getStaffList(callback))
app=webapp2.WSGIApplication([
('/staff',StaffHandler),
('/viewStaffList', StaffViewHandler)
], debug=True)
And then in my staff.js file, i did something like this:
viewMembersURL = "http://localhost:8030/viewStaffList";
$ (document).ready(function() {
$("#showMembers").bind('click', function(event) {
event.preventDefault();
doViewMembersRequest();
});
});
function doViewMembersRequest() {
$.ajax({
type: "GET",
url: viewMembersURL,
async: true,
jsonpCallback: 'handleResults',
contentType: "application/json",
dataType: 'jsonp'
});
}
function formatStaffList(members) {
var html = "<li><div>";
html+="<p><strong>" + members.id + "</strong></p>" +
"<h5>" + member.name + "</h5>";
html+="</div></li>";
return html;
}
function handleResults(members) {
var i, list="";
for (i=0; i<members.length; i +=1) {
list+=formatStaffList(members[i]);
}
displayMembers(list);
}
function displayMembers(list) {
$("#staff_members").html(list).listView();
}
and finally, the portion of my staff.html code where i want to display the list upon the click of a button:
<div data-role="content">
<ul data-role="listview" data-theme="b" data-inset="true">
Show Members
</ul>
<ul id="staff_members" data-role="listview" data-inset="true">
<!--Members list to go in here-->
</ul>
</div>
I'll really appreciate second thoughts on this.
Update:
I ran a couple of tests to see if i could display just the names.Somehow,i managed to get the listview to display this:
The number of items displayed matches the number of entities in my datastore. This means the communication with the server is fine. I think the problem is in the line
html+="<h5>" + members.name + "</h5>";
member.name isn't returning anything (tested with console.log()).
and if i change it to just
html+="<h5>" + members + "</h5>";
i get: [object Object] displayed in the listview. This tells me that am returning objects from the datastore and not strings as i would have expected.
The source code all looks good. A process of elimination would help to close in on what is probably a subtle problem. Trace execution of your code by inserting console.log('message') or alert('message') calls in the functions in staff.js, also appending the data you expect to see in order to validate your design. I use similar code that works with json rather than jsonp, so that may be a factor.
h5 tag is not closed properly while creating HTML.
function formatStaffList(members) {
var html = "<li><div>";
html+="<p><strong>" + members.id + "</strong></p>" +
"<h5>" + member.name + "</h5>"
html+="</div></li>";
return html;
}
I think the issue may be the sloppy handling of the id. You pull it from the request as a string, then use get_by_id() which wants an integer. And you store staff_id as an IntegerProperty but never cast it to a string when you build your strings. Take proper care of that. Use logging to make sure you are getting the results you expect at each process.
Phew.With the help of FireBug I finally got this to work.I noticed that in the bottom right corner this was being shown:
it dawned on me that needed to provide the key of the json objects, instead of the variables i had in my datastore. So instead of
html+="<h5>" + members.name + "</h5>";
it had to be
html+="<h5>" + members.Name + "</h5>";
or
html+="<h5>" + members.ID + "</h5>";
problem solved.
Name appears to be a keyword, so i'll just change that to something else.
The result now is exactly what i wanted.

Yelp API display only one ID using jQuery

Problem
I am trying to display the reviews of a Restaurant using Yelps API. I copied Smashing Magazines version of implementing API from their jQuery ebook. The problem is that using this method there are two stores being queried because the previous owners had the same phone number. Yelp can use phone numbers to query reviews and ratings. I need only the currently open store's reviews to display. I want to do it by some how showing Yelp's node elemnt ID. Each store has a unique identifier according to Yelps API and uses node element ID. The ID of the store i want to solely display is ID="Y6D43boKItksYx_d-RQL4g"
The Code Looks Like:
function showData(data) {
$.each(data.businesses, function(i,business){
// extra loop
var bizContent = '<p><img src="' + business.rating_img_url + '" img=""/><br>'+ business.review_count + ' reviews from Yelp.com</p>';
$(bizContent).appendTo('#yelpAVG');
$.each(business.reviews, function(i,review){
var content = '<div class="comments-block"><p>Posted by ' +review.user_name + ' on ' + review.date + 'via Yelp.com';
content += '<img src="' + review.user_photo_url + '" img=""/>';
content += '<p><img src="' + review.rating_img_url + '" img=""/><br>';
content += review.text_excerpt + '</p>';
content += '<p>Read the full review<br>';
$(content).appendTo('#yelpReviews');
});
});
}
function writeScriptTag(path) {
var yelpScript=document.createElement('script');
yelpScript.type='text/javascript';
yelpScript.src=path;
$("body").append(yelpScript);
}
$(document).ready(function(){
// note the use of the "callback" parameter
writeScriptTag( "http://api.yelp.com/phone_search?"+
"&categories.name=cafe"+
"&phone="+"(408) 292-2070"+
"&ywsid=Iua-78eDnxy0DTqm8I4mDw"+
"&limit=1"+
"&callback=showData");
});
Im a little new to jQuery so I wouldn't know where to begin or what I should start with to display queried results that only have
`ID="Y6D43boKItksYx_d-RQL4g"`
ShowOnly="id":"Y6D43boKItksYx_d-RQL4g" or something similar.
Thanks For Reading.
You can't with API vsersion 1.
but
With APIv2 you can query a specific business by id:
http://www.yelp.com/developers/documentation/v2/business
Some sample code to help you get started is available on github:
https://github.com/Yelp/yelp-api/blob/master/v2/js/business.html

Categories

Resources