AJAX Dynamic Buttons - ajax

Does anyone have suggestions on how to complete the following assignment? I've listed the instructions from the teacher below along with my JavaScript code. Thanks in advance!
Instructions:
The primary task is to dynamically generate the "genre" buttons that are currently hardcoded into the correlating HTML file.
The genre buttons should work the same way the hardcoded buttons currently work meaning they should have an event listener attached to them that should display podcasts from the ajax response that match the genre that was clicked.
JavaScript Code:
/**
* Ajax GET requester
*
*/
function get(url){
// Return a new promise.
return new Promise(function (resolve, reject){
// Do the usual XHR stuff
var req = new XMLHttpRequest();
req.open('GET', 'js/data.json');
req.onload = function(){
// This is called even on 404 etc
// so check the status
if(req.status === 200){
// Resolve the promise with the response text
resolve(req.response);
}else{
// Otherwise reject with the status text
// which will hopefully be a meaningful error
reject(Error(req.statusText));
}
};
// Make the request
req.send();
});
}
function get_podcasts(genre){
var url = 'js/data.json';
get(url).then(function (response){
var body = document.getElementById('mainContent');
response = JSON.parse(response);
if(response.results.length > 0){
body.innerHTML = '';
for(var i = 0; i < response.results.length; i++ ){
if(response.results[i].primaryGenreName === genre ){
var image = '<img src="' + response.results[i].artworkUrl100 + '">';
var image = document.createElement('img');
image.src = response.results[i].artworkUrl100;
body.appendChild(image);
body.innerHTML += '<div>' + response.results[i].trackName + '</div>' ;
}
}
}else{
body.innerHTML = 'No results found.';
}
console.log(response);
}, function (error){
console.log('No hits Found');
});
}
window.onload = function(){
//create an array with all button names
var genreNames = ['TV & Film', 'News & Politics', 'Society & Culture', 'Music', 'Hobbies'];
//loop through the array
for(var i = 0; i < genreNames.length; i++){
//create button element called "TV and Film" or whatever
var dynamicButtons = document.createElement('BUTTON');
var buttonText = document.createTextNode(genreNames);
//add it to the DOM (document)
dynamicButtons.appendChild(buttonText);
document.body.appendChild(dynamicButtons);
}
/*
for(i =0; i <= response.results.length; i++) {
for (key in response.results[i].primaryGenreName) {
if(response.results[i].primaryGenreName.hasOwnProperty(key)) {
output += '<li><button type="button">' + response.results[i].primaryGenreName + '</button></li>';
var update = document.getElementById('genres');
update.innerHTML = output;
}
}
}
*/
};

Related

Removing appended isotope items

I'm appending isotope items via Ajax in Wordpress:
My JS Code:
var $news_container = $('#news'); //The ID for the list with all the blog posts
$news_container.isotope({ //Isotope options, 'item' matches the class in the PHP
itemSelector: '.newsItem',
masonry: {
columnWidth: '.news-item-sizer',
gutter: '.gutter-sizer'
}
});
var has_run = false;
var init_offset = 0;
$('button.showall').click(function(e) {
e.preventDefault();
var button = $(this);
// Disable button
$(button).removeClass('showall');
$(button).addClass('showless');
// Record Nonce
var nonce = $(this).data("nonce");
if(has_run == false) {
button.data('offset', $(this).data("offset"));
init_offset = $(this).data("offset");
}
// Set AJAX parameters
data = {
action: 'mft_load_more_ajax',
init_offset: init_offset,
offset: button.data('offset'),
nonce: nonce
};
$.post(mft_load_more_ajax.ajaxurl, data, function(response) {
// Set Container Name
var response = JSON.parse(response);
console.log(response);
// Run through JSON
$.each( response, function( key, value ) {
// Set Value
var val = $(value);
// Set Container
var $container = $('#news').isotope();
// Append Val
$container.append(val).isotope( 'appended', val );
$(button).html('show less');
});
// Set Offset
var offset = button.data("offset");
button.data("offset", offset + 11 );
// If Has Run
has_run = true;
return false;
}
Until now, this works quite fine. Now I would like to switch the buttontext and it's class to .showless and on the next click all previously appended items should be removed. They all have the class .newsItem.appendedItem.
I tried this method:
$('button.showless').click(function(e) {
var button = $(this);
console.log('showless');
$out = $('.newsItem.appendedItem');
var isotopeInstance = $('#news').data('isotope');
isotopeInstance.$allAtoms = isotopeInstance.$allAtoms.not($out);
$out.remove();
// Disable button
$(button).removeClass('showless');
$(button).addClass('showall');
has_run = false;
return false;
});
Unfortunately this doesn't work, because the showless function is not even being entered, as I don't get a log in the console. What am I overlooking?
Thanks for your help!
Cara
Update 1:
I'm getting this error in Google Console.
Not sure, what was the problem now. But I cleaned the code a little bit with using an if statement, to check if the elements already got appended.
So my final code now looks like this:
var $news_container = $('#news'); //The ID for the list with all the blog posts
$news_container.isotope({ //Isotope options, 'item' matches the class in the PHP
itemSelector: '.newsItem',
masonry: {
columnWidth: '.news-item-sizer',
gutter: '.gutter-sizer'
}
});
var is_appended = false;
$('button.showall').click(function(e) {
e.preventDefault();
var button = $(this);
// Record Nonce
var nonce = $(this).data("nonce");
if(is_appended == false) {
button.data('offset', $(this).data("offset"));
// Disable button
button.prop( "disabled" , true );
// Set AJAX parameters
data = {
action: 'mft_load_more_ajax',
offset: button.data('offset'),
nonce: nonce
};
$.post(mft_load_more_ajax.ajaxurl, data, function(response) {
// Set Container Name
var response = JSON.parse(response);
console.log(response);
// Run through JSON
$.each( response, function( key, value ) {
// Set Value
var val = $(value);
// Set Container
var $container = $('#news').isotope();
// Append Val
$container.append(val).isotope( 'appended', val );
});
// Undo Button Disable
button.prop( "disabled" , false );
button.html('Weniger News anzeigen');
// Set Offset
// var offset = button.data("offset");
// button.data("offset", offset + 11 );
// If Was appended
is_appended = true;
return false;
});
} else if(is_appended == true) {
$out = $('.newsItem.appendedItem');
$news_container.isotope( 'remove', $out )
// layout remaining item elements
.isotope('layout');
button.html('Alle News anzeigen');
is_appended = false;
return false;
}
});
In Chrome everything works perfectly. But just figured out, that in Firefox my Ajax array is completely empty and I'm not able to fetch any data. Probably another problem, I'm going to post separately.

How to know if all uploads completed within a loop?

I have a code that works well for sending multiple files via ajax with FormData and XMLHttpRequest;
for (var i=0, j=this.files.length; i<j; i++) {
file = this.files[i];
var formdata = new FormData();
formdata.append("images[]", file);
var xhr = new XMLHttpRequest(),
upload = xhr.upload,
id = Math.floor((Math.random() * 100000));
upload.addEventListener("loadstart", function(e){
showUploadedItem(file, this.id);
});
upload.id = id;
upload.onprogress = function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
)
};
upload.onload = function(e) {
if (this.status == 200) {
console.log('');
}
};
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState ) {
console.log('');
}
};
xhr.open('post', '<?php echo Yii::app()->createUrl('url') ?>', true);
xhr.send(formdata);
}
I am sending each file as a new XMLHttpRequest object inside the loop, so I do not know when I'm getting all requests ending.
Can anyone help?
Take a look at the documentation for XMLHttpRequest.
There are a couple of options that I can think of. You could use the "loadend" callback for each of them and increment a variable outside of the loop and check for the total amount of requests that were sent in each one. Once the count reaches the total number of requests, you could perform any logic or call a function that would want to call.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest
Otherwise, setting the async parameter to false would work as well, but then you take a performance hit waiting for each one to finish before starting the others.
Based on your answer, my solution;
var x = 0;
var lenght = this.files.length;
for (var i=0, j=lenght; i<j; i++) {
// code here
var xhr = new XMLHttpRequest(),
// code here
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState && this.status == 200 ) {
x++;
if(x == lenght) {
window.setTimeout( function(){
alert('finish');
}, 1000 );
}
}
};
// code here
}
Though it is a trivial function, it works.

Ajax is correctly returning and displaying data but error message is being activated

I'm performing AJAX using the following code:
function main() {
// get the name fields
var name1 = document.getElementById("name1").value;
var name2 = document.getElementById("name2").value;
// Encode the user's input as query parameters in a URL
var url = "response.php" +
"?name1=" + encodeURIComponent(name1) +
"&name2=" + encodeURIComponent(name2);
// Fetch the contents of that URL using the XMLHttpRequest object
var req = createXMLHttpRequestObject();
req.open("GET", url);
req.onreadystatechange = function () {
if (req.readyState == 4 && req.status == 200) {
try {
// If we get here, we got a complete valid HTTP response
var response = req.responseText; // HTTP response as a string
var text = JSON.parse(response); // Parse it to a JS array
// Convert the array of text objects to a string of HTML
var list = "";
for (var i = 0; i < text.length; i++) {
list += "<li><p>" + text[i].reply + " " + text[i].name + "</p>";
}
// Display the HTML in the element from above.
var ad = document.getElementById("responseText");
ad.innerHTML = "<ul>" + list + "</ul>";
} catch (e) {
// display error message
alert("Error reading the response: " + e.toString());
}
} else {
// display status message
alert("There was a problem retrieving the data:\n" + req.statusText);
}
}
req.send(null);
}
// creates an XMLHttpRequest instance
function createXMLHttpRequestObject() {
// xmlHttp will store the reference to the XMLHttpRequest object
var xmlHttp;
// try to instantiate the native XMLHttpRequest object
try {
// create an XMLHttpRequest object
xmlHttp = new XMLHttpRequest();
} catch (e) {
// assume IE6 or older
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHttp");
} catch (e) {}
}
// return the created object or display an error message
if (!xmlHttp) alert("Error creating the XMLHttpRequest object.");
else return xmlHttp;
}
This works exactly as planned, the code within the try block is executed perfectly. But the alert "There was a problem retrieving the data: is also activated, with req.statusText displaying "OK".
How can this be possible? How can the code within the if statement activate perfectly but at the same time the else block is activated?
I'm stumped, any ideas?
The servor code is simply:
<?php
if( $_GET["name1"] || $_GET["name2"] ) {
$data = array(
array('name' => $_GET["name1"], 'reply' => 'hello'),
array('name' => $_GET["name2"], 'reply' => 'bye'),
);
echo json_encode($data);
}
?>
And the HTML:
<input id="name1">
<input id="name2">
<div id="responseText"></div>
<button onclick="main();">Do Ajax!</button>
Your conditional is probably being activated when req.readyState == 3 (content has begun to load). The onreadystatechange method may be triggered multiple times on the same request. You only care about what happens when it's 4, so refactor your method to only test when that is true:
var req = createXMLHttpRequestObject();
req.open("GET", url);
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status == 200) {
try {
// If we get here, we got a complete valid HTTP response
var response = req.responseText; // HTTP response as a string
var text = JSON.parse(response); // Parse it to a JS array
// Convert the array of text objects to a string of HTML
var list = "";
for (var i = 0; i < text.length; i++) {
list += "<li><p>" + text[i].reply + " " + text[i].name + "</p>";
}
// Display the HTML in the element from above.
var ad = document.getElementById("responseText");
ad.innerHTML = "<ul>" + list + "</ul>";
} catch(e) {
// display error message
alert("Error reading the response: " + e.toString());
}
} else {
// display status message
alert("There was a problem retrieving the data:\n" + req.statusText);
}
}
};
req.send(null);

Adding a .ajaxForm function to standard .ajax call

So I'm trying to find a method of getting a progress bar working on my .ajax call but not having much luck. I know that the ajaxForm plugin has the following code in it that allows for the uploadProgress option but the way my code works I'm not able to use that plugin. Is there anyway of adding the following code somehow so that it attaches to the standard .ajax call? Long shot I know!
// XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
function fileUploadXhr(a) {
var formdata = new FormData();
for (var i=0; i < a.length; i++) {
formdata.append(a[i].name, a[i].value);
}
if (options.extraData) {
var serializedData = deepSerialize(options.extraData);
for (i=0; i < serializedData.length; i++)
if (serializedData[i])
formdata.append(serializedData[i][0], serializedData[i][1]);
}
options.data = null;
var s = $.extend(true, {}, $.ajaxSettings, options, {
contentType: false,
processData: false,
cache: false,
type: method || 'POST'
});
if (options.uploadProgress) {
// workaround because jqXHR does not expose upload property
s.xhr = function() {
var xhr = jQuery.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position; /*event.position is deprecated*/
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
options.uploadProgress(event, position, total, percent);
}, false);
}
return xhr;
};
}
s.data = null;
var beforeSend = s.beforeSend;
s.beforeSend = function(xhr, o) {
o.data = formdata;
if(beforeSend)
beforeSend.call(this, xhr, o);
};
return $.ajax(s);
}
I do not guarantee on that, but try this:
xhr.upload.onprogress = function(event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
console.log("Progress: "+percent+"%"); //debug to see if the problem is there
options.uploadProgress(event, position, total, percent);
};
From posted code, I cannot even guess if the problem is in onprogress event handling or that options.uploadProgress, whatever it is.
I posted this as answer only because it wouldn't fit in comment.

Retrieve rows in crm2011 subgrid with JScript

As an JScript newbie, I have a problem with a subgrid in MS CRM 2011.
I have a form with a subgrid and in OnSave of that form, I want to loop over all the rows in the subgrid.
How can I do this with JScript ? Or is it possible another way, ex plugin ?
Thx
Here is the sample code which you can do on save of the form
var gridControl = document.getElementById('grdrelatedcontacts').control;
for (var intRowNumber = 0; intRowNumber < gridControl.getRecordsFromInnerGrid().length; intRowNumber++)
for (var intCellNumber = 0; intCellNumber < gridControl.getRecordsFromInnerGrid()[intRowNumber][3].cells.length; intCellNumber++)
alert(gridControl.getRecordsFromInnerGrid()[intRowNumber][3].cells[intCellNumber].outerText);
You can inspect the subgrid values on save by doing the following:
var gridControl = document.getElementById('subgrid_id').control;
var ids = gridControl.get_allRecordIds();
for(i = 0; i < ids.length; i++) {
var cellValue = gridControl.getCellValue('column_name', ids[i]);
// logic
}
Doing this on load is a bit more challenging since subgrids are loaded asynchronously and aren't likely to be done loading when the form onload event fires. You can check the grid periodically though to see when it's done loading by calling a function like the following in your form onload:
function subGridOnload() {
var grid = document.getElementById('subgrid_id');
if (grid.readyState!="complete") {
// delay one second and try again.
setTimeout(subGridOnload, 1000);
return;
}
// logic
}
Use a Rest call and retrieve the corresponding records :S
You can do something like this:
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.0/pws_streedandhousenodatas?$filter=_pws_streetandhousenumberid_value eq " + Xrm.Page.data.entity.getId(), true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
var results = JSON.parse(this.response);
for (var i = 0; i < results.value.length; i++) {
var pws_streedandhousenodataid = results.value[i]["pws_streedandhousenodataid"];
}
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send();
In this case the Xrm.Page.data.entity.getId() get you your current record id and you are looking all the lookups (that are in the sub-grid), you can also add some fields to select more info from them.

Resources