Displaying json data as a list in jQuery mobile - javascript

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.

Related

How to ignore Syntax Errors due to invalid token in the returned JSON in geocoding

I am sending a query to geocoding with state/country and getting a list of JSON responses. Sometimes the JSON doesn't get parsed properly. How can I ignore such result and just move on to the next one?
Here is the ajax call
$.ajax({
url: "/abc/points",
context: document.body,
data: {
latitude: places[0].geometry.location
.lat(),
longitude: places[0].geometry.location
.lng(),
distance: $(
'input[name="distance"]:checked')
.val(),
city: city1,
state: state1,
country: country1,
},
success: function(responseText) {
$("#response-div").html(
responseText);
$("#response-div")
.find("script")
.each(
function(i) {
eval($(
this)
.text());
});
$("html").removeClass(
"wait");
}
});
There are hundreds of results returned and I just want it to skip the ones that cause the syntax error and move on. I can post sample JSON text returned if you need it.
Thanks
COMMENT
Ok I was not able to find out if syntax errors can be ignored. So here is my next approach. Basically its a response that is getting parsed into JSON and its unable to ignore \n character in JSTL. I need to be able to replace \n as well as "," by "". Any help is appreciated. I know there are posts that explain how to ignore either of these, but not both at the same time.
function(marker, event, context) {
var contentString = '<div style="width:600px; height: 300px;">' +
'<div> <h4>' + '${fn:replace(object.name, search, replace)}' + ' </h4> </div>' +
'<table class="table">' +
'<tbody>' +
'<tr class="active">' +
'<td>Address: </td>' +
<c:set var="address" value="${object.stAddress} ${object.city}, ${object.state} ${object.zipcode}" />
'<td colspan=5>' + "${fn:replace(address, ",", " ")}"+"${fn:replace(address, "\n", " ")}" + '</td>' +
' </tr>' +
Edit
I have tried this and although it works to replace some other characters it fails to work for \n
<c:set var="search" value="'" />
<c:set var="replace" value="" />
<c:set var="newLn" value="\n" />
${fn:replace(fn:replace(address, newLn, replace), search, replace)}
Okay I was able to figure this out. Putting my solution here in case it helps anyone.
<c:set var="modAdd" value="${fn:replace(origAdd,newLn, "")}" />
Now in my code I just used this variable to perform double replacements.
${fn:replace(modAdd, "'", "")}

How do I set an attribute to a dynamically created button?

First and foremost, hello. I'm a college student and not a very experienced coder, so forgive me if I end up saying something really dumb.
Either way, I have a school project in which I have to create a functional website using Node.js, where people are able to log in and buy stuff.
Most of the stuff already works, but I am having trouble with a very specific thing which I simply cannot get to work, yet is essential to the project itself.
I import data from a mySql database into the website using AJAX, that data contains products that people can buy. Then, those products are appended to the HTML page itself, and dynamically create two buttons for each product that is appended, one which says "Buy Now" and the other which says "Learn More".
Now, those buttons are supposed to be somehow associated to the values of the database, but I have no idea how to do this.
$(document).ready(function () {
$(function () {
$.ajax({
type: 'POST',
url: 'http://localhost:3000/getPacotes',
success: function (data) {
console.log(data);
for (var i = 0; i < data.length; i++) {
var pacoteSet1 = "<div class='col-md-4 pacotes'>";
var pacoteSet2 = "<input id=btnPac"+
i + " type='button' name='comprar' value='Comprar Pacote'>";
var pacoteSet3 = "</div>";
var idPacote = data[i].idPacote;
var nomePacote = data[i].Nome_Pacote;
$("#pacotes").append(pacoteSet1 +
"<h1>" + nomePacote + "</h1>" +
"<h1>" + nomePacote + "</h1>" +
"<h3>" + precoPacote + "euros/mes </h3>" +
pacoteSet2 +
pacoteSet3);
}
}
});
});
});
My teacher told me to give an attr to the buttons I create, and that's what I was pretty much trying to do now, but I dont know how to do that, I mean, if the buttons were static it would be pretty easy, but since the buttons are not there when the document is created, I dont know if this will work
$("#btnPac" + i).attr({"id": idPacote,
"nome": nomePacote,
"preco": precoPacote,
});
Anyway, Hopefully, I didn't sound too dumb and thanks in advance
TL:DR how do I give an attribute to a dynamically created button
You just need to change your jquery function like below:
$(document).find("#btnPac" + i).attr({"id": idPacote,
"nome": nomePacote,
"preco": precoPacote
});
This should be your solution.
You can do that while creating the html for button element. By using string concatenation, which you are already using while setting the ID:
var pacoteSet2 = "<input id=btnPac"+ i + " nome='" + nomePacote + "' preco='" + precoPacote + "' type='button' name='comprar' value='Comprar Pacote'>";
Overloading the HTML with attributes is a bad idea in my opinion. You could create the Elements in JS, bind the data to it, and then append the button to the dom. Thats quite easy with jquery:
var button=$("<button>Show More</button>");//create
button.on("click",showMore.bind({name:"test"}));//add listener
$(document.body).append(button);//append
function showMore(){
alert(this.name);
}
You can create a new input tag and set these attributes then append to your div with this code:
$('<input/>', {
id: 'btnPac' + i,
nome: nomePacote ,
preco: precoPacote ,
type: 'button'
}).appendTo("#pacotes");
You can do the same for your others (h1, h3)

Add data to self created HTML object

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>

Elements prepended using jQuery .get() while looping through array are loaded in different order on page refresh

I want to show a subsection of some projects on my webpage. I have an array of project names and some corresponding data in html files, like in the example below. I have a button with some preview-content in it, and if a user clicks on that it opens up the full container with all the project details.
To do this I though to loop through a sliced array in reverse and prepend the code to a div element on my webpage. The content often loads fine, but sometimes when I refresh the page it will display the previews in a different order than as defined in the array. Also, sometimes "previewtitle" and "previewcontent" return undefined, but not all the time. What am I doing wrong here?
I want to prepend the projects dynamically in the same order on every refresh.
var $projectNames = [ "coolprojecthere", "andanotherone", "moreprojects", "lastone" ];
projects/coolprojecthere.html looks like this:
<div id="title">Project title here</div>
<div id="content">Content html here</div>
projects/previews/coolprojecthere.html looks like this:
<div id="title">Project title here</div>
<div id="content">Content text here</div>
I loop through them like this to prepend them:
$projectNames = $projectNames.slice(0, 7);
$.each($projectNames.reverse(), function (index, projectname) {
var previewtitle, previewcontent;
$.get("projects/previews/" + projectname + ".html", function (prevdata) {
previewtitle = $(prevdata).filter('#title').text();
previewcontent = $(prevdata).filter('#content').text();
});
$.get("projects/" + projectname + ".html", function (data) {
var project = "<section id=\"project\" class=\"\"> \
<t>" + previewtitle + "</t><br /> \
<p>" + previewcontent + "</p> \
</div> \
<div class=\"content\"> \
<h5>" + $(data).filter('#title').text() + "</h5> \
<div class=\"content-container\">"
+ $(data).filter('#content').html() +
"</div> \
</div> \
</section>"
$('#main-container').prepend(project);
});
From the jQuery Documentation you must specify async option to be set to false to get a synchronous AJAX request.
$.ajax({ url: 'projects/previews/" + projectname + ".html',
async: false,
dataType: 'json',
success: function(data) {
// your code here
}
});
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false.
Otherwise, you could also do the jQuery's AJAX setup, and set it in synchronous mode by calling once (above your initial code):
jQuery.ajaxSetup({async:false});
It will perform all your further AJAX calls in synchronous mode. You can continue using jQuery.get(); method as you did before.
Note: Please read Felix Kling's answer, about when synchronous calls might be a bad idea.
Making the Ajax calls synchronous is a bad idea. Instead, you should chain and nest them, so that each one is executed after each other.
Lets organize your code a little more, using promises:
function getPreviewData(projectName) {
return $.get(
"projects/previews/" + projectname + ".html"
).then(function(prevdata) {
return {
title: $(prevdata).filter('#title').text(),
content: $(prevdata).filter('#content').text()
};
);
}
function getProjectHTML(projectName, previewTitle, previewContent) {
return $.get("projects/" + projectname + ".html").then(function (data) {
// ...
});
}
$projectNames = $projectNames.slice(0, 7);
var head = new $.Deferred();
var chain = head.promise();
$.each($projectNames.reverse(), function (index, projectName) {
chain = chain.then(function() {
return getPreviewData(projectName).then(function(previewData) {
return getProjectHTML(projectName, previewData.title, previewData.content);
});
});
});
head.resolve();

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.

Categories

Resources