jquery html() not setting div contents - javascript

I am making my first app using Parse.com for database storage, and I am using the Parse JavaScript SDK to make use of this database.
I am trying to populate a list of items from one of my database tables, and this table contains a field which is a pointer to an object of another class/table. I need to retrieve a field from this object in order to display the information properly.
However, Parse seems to require me to request each of these objects separately from my main query on the table. Anyway, so I make the request and have a success callback which uses jquery's .html() to set the contents of a div which is id'd by the id of the retreived object.
The problem is, after the work is done, the div is rendered empty. Although, oddly, I tried using calls to alert to get the contents of each div within the success callback, and the contents was not only correct after I had called .html() but also before I called it. Though, that's probably down to JavaScripts asynchronous function calls.
Here is the function in question:
function updateBudgets() {
var Budget = Parse.Object.extend("Budget");
var query = new Parse.Query(Budget);
query.equalTo("User", Parse.User.current());
//query.include(["Budget.Category"]); //I tried this to include the category object with the query response, but it didn't seem to work
query.find({
success: function(result) {
var opt = "<h2>Budgets</h2>";
var category, id;
for(var i = 0; i < result.length; i++) {
category = result[i].get("Category");
category.fetch({
success: function(cat) {
alert($('#' + cat.id).html());
$('#' + cat.id).text(cat.get("Name"));
alert($('#' + cat.id).html());
}
});
opt += makeBudget(category.id, parseFloat(result[i].get("Amount")/100), result[i].get("Balance"), result[i].id);
}
$('#budgets').html(opt);
}
});
}
I tried what the documentation seemed to suggest was the equivalent of an SQL JOIN operation using the .include() function on my query, but it didn't seem to work at all.
So, what I would like to know is either how I can debug my JavaScript such that I can get around this strange behaviour with .html() or how I can properly do this JOIN style operation with Parse. What Documentation I have found doesn't really go into a whole lot of detail.
I would be very grateful for any help.

Please consider the following "test guide" more as comment than an answer, because it just contains some console.log statements instead of an actual answer for your problem.
Anyway below are some issues I'd try to checkout:
do you receive an answer from the server following query.find
check is data fetched (inner query) from the server
check if category data is received successfully following fetch query
check if element with category id is found
error handling added for fetch and query
Also I noticed that you are using .text() method for setting the value. I think it'll work fine as long as the element in question is not a form input element. If that's the case, you probably have to you use .val() method.
The console.log test print outs that I added can be found at this Fiddle for updateBudgets() function. (Fiddle updated) I hope this helps :-)

Related

What's the correct way to send Javascript code along with rendered HTTP to a client?

Mid development I decided to switch to server-side rendering for a better control amongst other benefits. My web application is completely AJAX based, no url redirecting, so the idea here is a website that builds itself up
I just couldn't figure out the proper way to send javascript events/functions along with the html string, or should all the necessary javascript always be preloaded in the static files?
Let's say client clicks a pre-rendered button 'open table'
The server will make a query, build the html table and send it back, but this table also needs javascript triggers and functions to work properly, how are these sent, received and executed?
There are a couple of articles that mention to not use eval() in Javascript, is there any way around this? I don't want to have to preload unnecessary events for elements that don't yet exist
The server is Python and the Client is Javascript/JQuery
Theoretical example :
Client Base Javascript :
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
eval(response.javascript()); //??
}
});
Python Server(views.py) :
def get_table(request):
data = {}
#String containing rendered html
data['html'] = get_render_table()
#String containing Javascript code?
data['javascript'] = TABLE_EVENTS_JAVASCRIPT
return HttpResponse(json.dumps(data),content_type='json')
Worth noting my question comes from an experimental/learning perspective
Update:
You can use jQuery.getScript() to lazy load JS. I think this solution is as close as you can get to run JS without using eval().
See this example:
jQuery.getScript("/path/to/script.js", function(data, textStatus, jqxhr) {
/* Code has been loaded and executed. */
console.log( data ); // Data returned
console.log( textStatus ); // Success
console.log( jqxhr.status ); // 200
console.log( "Load was performed." );
});
and "/path/to/script.js" could be a string returned from $.getJOSN response.
Also, the documentation for getScrippt() has examples on how to handle errors and cache files.
Old Answer:
Using .on() attaches events to current and future DOM elements.
You can either attache events prior to DOM insertion or attache event after DOM insertion.
So in your example you can do something like:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
var code = $(response.html);
code.find(".elementToFind").on("click", function (){
// Code to be executed on click event
});
$("#table_div").append(code);
}
});
I did not test the code but I think it should work.
Assuming you can't just set up an event-binding function and then call it from the main script (the JavaScript you need can't be guessed ahead of time, for example) then one really easy way is just to append the JavaScript to the bottom of the returned HTML content within script tags. When it's appended along with the HTML, the script should simply execute, with no eval() required.
I can't swear that this would work in old browsers, but it's a trick I've used a couple of times, and I've had no problems with it in Firefox, Chrome, or any of the later IE versions.
I think I see what you're asking here, from my understanding you want to send the new "page" asynchorously, and render the new javascript and html. It looks like you already got your request/response down, so i'm not gonna go and talk about sending JSON objects, and the whole "how-to" of sending html and javascript because it looks like you got that part. To do what you want and to dynamically add your javascript in, this stackoverflow question looks like it has what you need
Is there a way to create a function from a string with javascript?
So pertaining to your example, here is how it would look when you recieve the JSON string from your python script:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
/* Create function from string */
var newFunction = Function(response.javascript['param_1'], response.javascript['param_2'], response.javascript['function']);
/* Execute our new function to test it */
newFunction();
}
});
*Your actual function contents would be the string: response.javascript['function']
*Your parameter names if any would be in separate strings ex: response.javascript['param_1']
That is almost a direct copy of the "String to function" code that you can see in the linked question, just replaced it with your relevant code. This code is also assuming that your object is sent with the response.javascript object containing an array with your actual function content and parameter names. I'm sure you could change the actual name of the var too, or maybe put it in an associative array or something that you can keep track of and rename. All just suggestions, but hopefully this works for you, and helps you with your problem.
I am also doing similar work in my project where I had to load partial html using ajax calls and then this partial HTML has elements which requires events to be attached. So my solution is to create a common method to make ajax calls and keep a js method name to be executed post ajax call in html response itself. For example my server returns below html
<input type="hidden" data-act="onPartialLoad" value="createTableEvents" />
<div>.........rest of html response.....<div>
Now in common method, look for input[type='hidden'][data-act='onPartialLoad'] and for each run the method name provided in value attribute (value="createTableEvents")
Dont Use Eval() method as it is not recommended due to security
issues. Check here.
you can run js method using window["method name"]...so here is a part of code that I use.
$.ajax(options).done(function (data) {
var $target = $("#table_div");
$target.fadeOut(function () {
$target.html(data);
$target.fadeIn(function () {
try {
$('input[data-act="onPartialLoad"]', $target).each(function () {
try {
//you can pass parameters in json format from server to be passed into your js method
var params = $(this).attr('params');
if (params == undefined) {
window[$(this).val()]();
}
else {
window[$(this).val()]($.parseJSON(htmlutil.htmlDecode(params)));
}
} catch (e) {
if (console && console.log) {
console.log(e.stack);
console.log($(this).val());
}
}
});
}
catch (e) {
console.log(e.stack);
}
});
});
});
use jQuery.getScript() (as suggested by Kalimah Apps) to load the required js files first.

Backbone where returns empty in fetch callback

I'm having an odd error where a backbone where function (Titanium Alloy, kinda homogeneous) returns empty while the fetch method returns a list of models. Ive checked over and over again, I tried putting the where function in the success callback of the fetch method but STILL it results in an unresolvable error
Alloy.Collections.favorites.fetch({
success: function(collection) {
console.log(JSON.stringify(collection));
console.log(self.get('id'));
var favorite = collection.where({
jobId: self.get('id')
});
console.log(JSON.stringify(favorite));
});
The above output is:
[{"jobId":5162179,"dateAdded":1414590144,"candidateId":99,"id":19},{"jobId":5161302,"dateAdded":1414588983,"candidateId":99,"id":17},{"jobId":5161437,"dateAdded":1414588785,"candidateId":99,"id":16}]
5161437
[]
How can the above happen? How can somebody reproduce this? Is the collection being occupied or is it a bug within Titanium Alloy? This process is part of a databind on a view (view A) and this exact code works on a different part where the only difference is that view A is not directly influenced by changes in the collection.
Any help? Is this even possible with backbone? I cant get my head around this
APPARENTLY the .where function strictly compares 2 values (=== operator) and the id i gave was in the form of a string while the id within the collection was an integer. Too bad the backbone documentation doesnt state this information

Get ajax value from JavaScript function

I'm not an JS developer, so forgive me if this is a stupid question.
I have this web application, that uses ajax to keep the data update on the screen, but I'm not able to use the ajax value in my JS function, the code generated by my application is:
<span id="c0"></span>
In the web page I just see the numeric value, e.g. 5 and it's updated every second as expected, so I tried to use the same in my JS function:
<script type="text/javascript">
function getPoint()
{
console.log ('<span id="c0"></span>');
return 0;
}
</script>
But in the Chrome's log I just see <span id="c0"></span> instead of a numeric value.
Try the following:
<script type="text/javascript">
function getPoint()
{
var span_element = document.getElementById("c0");
var content = span_element.innerHTML;
console.log(content);
return content;
}
</script>
Explanation:
First you need to access the DOM element of javascript. You identified the element with the id: "c0". To access the element you need to use the function: document.getElementById("someID");
With the element you can do a lot of things. In this case you want to access whatever is inside the tag , so what you want is its inner HTML.
If you are using JQuery, you can also get its content like this:
var span_element = $("#c0");
var content = span_element.text();
Console.log simply logs whatever string you send it as a parameter. So what you are seeing is the expected behavior.
Assuming you are using jQuery, and the ajax returned value is being displayed in the span (id = "c0"), this console.log statement should work:
console.log($("#c0").text());
$("#c0") returns the jQuery object using the id selector (#).

Fine Uploader referencing newly created DOM object in onComplete callback

I've been messing around with this for quite some time. The deeper I get the more tweaks I need to make. My biggest issue id being able to correctly reference the created li item once it is created.
For exampled once an image is uploaded a new li item is created. Then I reference this li element to make various changes. Such as add in thumb nail and custom buttons. This reference is required for various reasons.
Most of everything is working fine from deleting to error output etc. However the way I find reference to the corresponding li element is broken.
From what I can tell on complete is as such
onComplete(String id, String name, Object responseJSON, XMLHttpRequest xhr)
There is no much data on this but from I can gather the ID is a number represented the uploaded image in the order of the list. Possibly an internal list which would mirror the outputted list.
So I've been marrying up this id with the index id of the array of li elements. This has allowed me to the located the correct completed li element and manipulate it.
So this works fine. The issue is when I'm deleting images. Image are deleted and then the li elements removed. However the issue is that the onComplete ID does not marry up with the with the index within the list.
I'm using a custom delete function as my images are saved in a database and other reasons. I will also run into the same issue when prepoluating the list. Currently I plan to pre-output a copy of the list with the relevant data in exactly the same way. I cannot find any information on prepopulating the fineuplader.
So is there a way to accurately reference the newly complete li elements? Once that is constant on most browsers? How is the best way to prepopulate the list?
Really a simple reference within the oncomplete handler to the new dom li element would be perfect. Or anything similar. I'm surprised it does not exist. Maybe it does but I cannot find any info on it.
Thanks
I'm going to assume you are using the default Fine Uploader UI, and not FineUploaderBasic/core. In that case, it's quite easy to get a handle on the DOM element Fine Uploader creates for the associated file. For example, in an onComplete callback:
....
onComplete: function(id, name, response, xhrOrXdr) {
var listItemEl = this.getItemByFileId(id);
// do something with this element
}
I've provided a non-jQuery example since your example code does not seem to use jQuery, even though you have tagged this question as jQuery. In case you are using the jQuery plug-in, your code would look something like this:
$('#myFineUploaderContainer').on('complete', function(event, id, name, response, xhrOrXdr) {
var $listItem = $(this).fineUploader('getItemByFileId', id);
// do something with this jQuery object
});
Note that, in the above example, Fine Uploader versions 3.6 and older will return a Node/HTMLElement, while Fine Uploader 3.7 and newer will return the expected jQuery object. I wrote the above example assuming you are using 3.7.
For more information on this and other API methods, options, and callbacks, see the documentation at http://docs.fineuploader.com.

I can't seem to receive my JSON object correctly

Sorry for the badly worded title, and I would also like to apologize in advance if my explanation is lackluster. My knowledge of JavaScript and Ajax stuff isn't really that great.
Anyway, so, what I am trying to do is display a list of items using PHP, and then when an item is clicked, a popup will be displayed basically asking if the users want to add the items to the DB (it's essentially importing from one DB to another). Part of the popup is a drop down list that contains possible parents for the imported items. (So, if you are importing a project called Vista, you might place it in the parent category 'OS').
In order to make the drop down, an ajax request must be made, and the back end PHP replies with a JSON object which contains all elements that need to be included in the drop down.
So, as a test to see if the AJAX connection works, I just arbitrarily place a button on the window like so:
<div align="center" onclick="test()">TEST BUTTON </div>
and have a JS function called test:
function test(){
var url = "index.php?module=getlist";
//Code to send post request with a callback to function test2();
}
and a function test2():
function test2(data){
if (data){
alert(data.Project[0].id);
}
else {
alert("ERROR");
}
}
Note: The PHP code returns a JSON object and one of the sub-object thingies is called Project which is an associate array with fields like id and name.
The above works. The alert box shows a number that corresponds to a project id.
But, we want to have a popup that contains the list! So, we get some html like this:
<td align="center" onclick="collection('Random_Name', 'Random_Description')">Project 1</td>
Note: I am passing the values for the item Name and Description to a JS function called collection.
function collection(name, description){
test();
//Stuff that creates the popup, creates a form in the popup, and populates the form with default values(name and description).
// Following Stuff is used to make the drop down.
var tempdata = new Array(new Array());
tempdata[0]['name'] = json.Project[0].name;
tempdata[0]['value'] = json.Project[0].id;
//This function creates the Select list, it requires a name, default value, and
//a multi-dimensional array like the one defined above.
var pacolist = createSelect("collection_list",'',tempdata)
//Append the elements together and add a save button.
}
To try and get this to work, I declared a global variable called json at the top of the page. I changed the alert(data.Project[0].id); in test2() to json = data;
But, it didn't work.
I get an Uncaught TypeError: Cannot read property 'Project' of undefined error when I click to open the popup.
I changed the test2() method to be like this instead:
function test2(data){
if(data){
return data
}
else{
//Code from the original test() function to send post request to PHP with
//a callback to test2.
}
and in the collection() function, I added this: var json = test2,(No global json) but that did not work either.
Sorry for the long winded question, but basically, I open a function, the function needs to call another function that sends a post request and the data received by the request needs to be used by the original function. How do I do this?
I think this is just a time issue. As in the request takes a while, and in the mean time, the original function has already moved on.
EDIT: Found a solution. I think it was a timing issue. In order to fix it. I made the page html call a function that stored the name and description as global variables. This function then made the post request with a callback to a different function. This different function then used the data (the JSON object) it received and passed it along with the global name and description to the collection() function mentioned earlier.
You have to parse the data before you use it.
//For IE6/IE7
var data = eval('(' + json + ')');
//For IE8+/Chrome/Firefox...
var data = JSON.parse(json);

Categories