How to appropriately apply styles to a functioning get request using JQuery? - javascript

So here's whats going on, I have a couple scenarios where I can't seem to apply any styles to content coming from a get request, and on one of them I managed to be able to but it wouldn't be considered best practice.
Premise:
I have an empty Ul to which Li's will be attached from a GET request to an API.
Scenarios
1) I create DOM objects using JQuery and append LI <-- SPAN <-- string to the empty UL and then state that all the children of the UL will be colored green.
(this does not work & yes I could target the UL and have everything inherit the styles but that wont work for what I have in mind)
2) I append a string which contains HTML markup within it to then add styles and concat them with what the GET request spits out. ( for some reason it seems to work this way but I really don't want to be creating LI's and SPANS + classes all in one string)
//scenario 1
var $orders = $("#orders");
$.ajax({
type: 'GET',
url: 'http://rest.learncode.academy/api/johnbob/friends',
success: function (data) {
$.each(data, function (i, item) {
if (item.name && item.drink) {
var $spn = $("<span></span>");
var $lli = $("<li></li>");
// $spn.append(String(item.name));
$spn.css({width: "20px"});
$orders.append($lli).append($spn).append("name: "+item.name+", Order: " + item.drink);
$orders.children().css({ color: "green" });
console.log($spn);
}
})
}
});
/* scenario 2
var $orders = $("#orders");
$.ajax({
type: 'GET',
url: 'http://rest.learncode.academy/api/johnbob/friends',
success: function (data) {
$.each(data, function (i, item) {
if (item.name && item.drink) {
var $spn = $("<span>hell</span>");
var $lli = $("<li></li>")
// $spn.append(String(item.name));
$spn.css({width: "20px"});
$orders.append("<li>Name: <span class='tato'>" + item.name + ",</span> Order: " + item.drink + "</li>");
$orders.children().css({ color: "green" });
console.log($spn);
}
})
}
});
*/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Coffee Orders</h2>
<br />
<ul id="orders">
<li>control group</li>
</ul>
<br />
<h4>Add a coffee order</h4>
<p>name: <input type="text" id="name"></p>
<p>drink: <input type="text" id="drink"></p>
<button id="add_order">Add!</button>
I haven't been able to find a reliable answer as to why this is happening, eventually I'll want to line up the orders regardless of the name length using a span.
edit:
What was happening (as stated in the answer) was I was appending empty LI's SPANs and Strings to the original UL. When using append() keep in mind anything you add (in a chain form) will be appended to the original stated element and not the previous one.
Side note:
For more information on better practice of templating incoming GET stuff check out this vid I found.
https://www.youtube.com/watch?v=GbNWPn8vodo&index=9&list=PLoYCgNOIyGABdI2V8I_SWo22tFpgh2s6_

As noted by #Taplar the issue is use of .append(). You are appending <span> elements and #text nodes to <ul> at
$orders.append($lli).append($spn).append("name: "+item.name+", Order: " + item.drink);
which are not valid child elements of <ul>
Permitted content zero or more <li> elements, which in turn often
contain nested <ol> or <ul> elements.
To correct issue, set #text node as .innerHTML of <span> element, and span element as .innerHTML of <li> element using html of jQuery(html, attributes) function attributes property.
Also set span css display property to block for width property to be applied to the element.
//scenario 1
var $orders = $("#orders");
$.ajax({
type: 'GET',
url: 'http://rest.learncode.academy/api/johnbob/friends',
success: function(data) {
$.each(data, function(i, item) {
if (item.name && item.drink) {
var $spn = $("<span></span>", {
html: "name: "
+ item.name
+ ", Order: "
+ item.drink,
css: {
width: "20px",
display: "block",
position: "relative"
}
});
var $lli = $("<li></li>", {
html: $spn
});
$orders.append($lli)
.children().css("color", "green");
}
})
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Coffee Orders</h2>
<br />
<ul id="orders">
<li>control group</li>
</ul>
<br />
<h4>Add a coffee order</h4>
<p>name:
<input type="text" id="name">
</p>
<p>drink:
<input type="text" id="drink">
</p>
<button id="add_order">Add!</button>

Related

How to get selected li value

I have an array list as shown below
var items = ['Iphones', 'Samsung', 'Huawei'] which I append to a li as below.
HTML & JS
<div id="host">
<div class="data_box"></div>
</div>
$.ajax({
dataType: 'json',
success: function (results) {
$('.data_box').html('<li class="li_of_phones">'+results.toString().split(',').join('<br/>')+'</li>').slideDown();
},});
<script>
$('#host').on('click', '.li_of_phones', function () {
console.log($(this).text());
});
</script>
When I try to get the selected li when user clicks, it returns the array i.e Iphones,Samsung,Huawei instead of the selected phone (may be iphones)
Why am I not getting the selected phone when user clicks on the li but then it returns the all phones in the array to user?
It seems you receive the results from the ajax call as a comma separated string and then set it in a single <li> element with the li_of_phones class.
You could loop the splitted response in a foreach and create different li elements for each result.
const results = 'Iphones, Samsung, Huawei';
let phonesList = '';
results.split(',').forEach(phone => {
phonesList += '<li class="li_of_phones">' + phone.trim() + '</li>';
});
$('.data_box').html(phonesList).slideDown();
$('#host').on('click', '.li_of_phones', function () {
console.log($(this).text());
});
.as-console-wrapper { max-height: 5.5em !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="host">
<ul class="data_box"></ul>
</div>
You might have to change some css styles of the resulting list items.
You should add an event on li. I have created a small example.
$('li').click(function(e) {
console.log(e.target.innerHTML);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>

DOM not updating on GET request + data-attributes

Issue: Upon updating the src of images, retrieved via GET request, the DOM never updates but their new values show in console.
Suspected Cause: I think there is some conflict with using data-attributes, but using attr() instead of data() does not seem to remedy.
HTML to be updated:
<div class="data-block">
<img data-item="hp-logo" />
<img data-item="hp-banner" />
</div>
GET Request:
if(promoid != null) {
$.get({
url: '/snippets/data.html',
cache: false
}).then(function(data){
var tempData = $('<output>').append($.parseHTML(data)).find('.data[data-promo-id="' + promoid + '"]');
myContent = tempData.html();
dataItems = $('.data-block').html();
//console.log('Data Items On Page: ', dataItems);
$(dataItems).each(function (index, value) {
if( $(this).is('[data-item]')) {
//console.log('Data Items With Attribute: ', this);
dataItemLookup = $(this).attr('data-item');
//console.log('Data Item Lookup Value: ', dataItemLookup);
$(myContent).each(function (index, value) {
//console.log('Retrieved Items Checking Against: ', this);
if ( $(this).attr('data-alias') == lastalias ) {
//console.log('Retrieved Items Match Alias: ', this);
if ($(this).attr('data-item') == dataItemLookup) {
//console.log('Retrieved Item Match', this);
dataImageDesktop = $(this).attr('data-image-desktop');
//console.log('Value to be Passed to Data Item: ', dataImageDesktop);
} else {
// Do nothing
}
} else {
// Do nothing
}
});
$(this).attr('src', dataImageDesktop);
console.log(this);
}
});
});
}
data.html:
<div class="data-container">
<div class="data" data-promo-id="11202016">
<div data-alias="test.html" data-item="hp-logo" data-image-desktop="http://placehold.it/250x150"></div>
<div data-alias="test.html" data-item="hp-banner" data-image-desktop="http://placehold.it/350x250"></div>
<div data-alias="not-test.html" data-item="hp-spot" data-image-desktop="http://placehold.it/450x350"></div>
</div>
</div>
Not sure how to proceed in troubleshooting this issue. Everything works as expected, except the DOM updating. Ideas?
Using html() on an element will get you the innerHTML of the object, which is a string. As such using it inside $() later will cause jQuery to create new elements that are not attached to the DOM. If all you are after is to select elements and modify them, simply use the $(selector) and modify it. Do not use html() and wrap the results with $().
Instead of $(selector).attr('data-name') try using $(selector).data('name') as shown in the jQuery.data() documentation.

div sort not working when div generated dynamically

I'm trying to sort a list of divs with the properties shown by particular attributes (gender, level, name etc) using the following script:
html:
<div id="sortThis" class="col-xs-12 alert-container">
<div id="1" class="container-element sortable box box-blue" data-gender="1" data-level="4" data-name="AAA"> <h3>AAA</h3><div class="panel-body">AAA is resp</div>
</div>
<div id="2" class="container-element sortable box box-pink" data-gender="2" data-level="3" data-name="DDD"><h3>DDD</h3><div class="panel-body">DDD is a s</div>
</div>
<div id="3" class="container-element sortable box box-blue" data-gender="1" data-level="2" data-name="FFF"><h3>FFF</h3><div class="panel-body">FFF has mad</div>
</div>
<div id="4" class="container-element sortable box box-pink" data-gender="2" data-level="4" data-name="CCC"><h3>CCC</h3><div class="panel-body">CCC has ma</div>
</div>
<div id="5" class="container-element sortable box box-pink" data-gender="2" data-level="2" data-name=EEE><h3>EEE</h3><div class="panel-body">EEE is a f</div>
</div>
<div id="6" class="container-element sortable box box-blue" data-gender="1" data-level="3" data-name="BBB"><h3>BBB</h3><div class="panel-body">BBB is an ou</div>
</div>
</div>
<button id="sLevel" class="LbtnSort">Sort by Level</button><br/>
<button id="sGender" class="GbtnSort">Sort by Gender</button><br/>
js:
var LdivList = $(".box");
LdivList.sort(function(a, b){
return $(a).data("level")-$(b).data("level")
});
var GdivList = $(".box");
GdivList.sort(function(a, b){
return $(a).data("gender")-$(b).data("gender")
});
/* sort on button click */
$("button.LbtnSort").click(function() {
$("#sortThis").html(LdivList);
});
/* sort on button click */
$("button.GbtnSort").click(function() {
$("#sortThis").html(GdivList);
});
when the .sortable divs are static, the sort works fine, as this jfiddle shows, however if the contents of the #sortable div (i.e. .sortable divs) are dynamically generated (in this case as the result of a form submit), when the sort button is pressed, the entire contents of the #sortable div disappears, and I can't seem to get it to work.
Any help or suggestions would be appreciated.
edit: The code for dynamic generation of the list is as follows - effectively it's an AXAX form submit that pulls data from a sorted list of items and outputs them.
$('#formStep2').submit(function(event) {
// get the form data
var studentArray = [];
$(".listbox li").each(function() {
studentArray.push({
'name': ($(this).text()),
'gender': ($(this).closest('ol').attr('id')).substr(0, 1),
'level': ($(this).closest('ol').attr('id')).substr(2, 3),
'topic': ($('input[name=topic]').val())
})
});
var studentString = JSON.stringify(studentArray);
console.log(studentString);
var formData = {
'students': studentString,
};
// process the form
$.ajax({
type: 'POST', // define the type of HTTP verb we want to use (POST for our form)
url: 'process_step2.php', // the url where we want to POST
data: formData, // our data object
dataType: 'json', // what type of data do we expect back from the server
encode: true
})
// using the done promise callback
.done(function(data) {
if (!data.success) {
// error handling to go here.....
} else {
$('.alert-container').empty();
var obj = JSON.parse(data.message);
//sort the array alphabetically by name (default status)
var test = obj.sort(function(a,b){
var lccomp = a.name.toLowerCase().localeCompare(b.name.toLowerCase());
return lccomp ? lccomp : a.name > b.name ? 1 : a.name < b.name ? -1 : 0;
});
console.log(test);
var i=0;
test.forEach(function(st) {
console.log(st['name']);
var gen = (st['gender'] == 1) ? "blue" : (st['gender'] == 2) ? "pink" : NULL;
$('.alert-container').append('<div id="' + (i+1) + '" class="container-element sortable box box-' + gen + '" data-gender="' + st['gender'] + '" data-level="' + st['level'] + '" data-name="' + st['name'] + '"><h3>' + st['name'] + '</h3><div class="panel-body"><div class="col-xs-9"><i class="fa fa-quote-left fa-3x fa-pull-left fa-' + gen + '" aria-hidden=:true"></i>' + st['comment'] + '</div></div></div>');
i++;
});
// jump to the next tab
var $active = $('.wizard .nav-tabs li.active');
$active.next().removeClass('disabled');
nextTab($active);
}
})
// using the fail promise callback
.fail(function(data) {
// show any errors
// best to remove for production
console.log(data);
});
// stop the form from submitting the normal way and refreshing the page
event.preventDefault();
});
You are defining LdivList and GdivList inline with your code so they are defined on DOM ready. You have to wrap the definition of those inside a function and call it on click:
$(document).ready(function(){
$("button.LbtnSort").click(function() {
$("#sortThis").html(GenerateLdivList);
});
/* sort on button click */
$("button.GbtnSort").click(function() {
$("#sortThis").html(GenerateGdivList());
});
});
function GenerateLdivList(){
var LdivList = $(".box");
LdivList.sort(function(a, b){
return $(a).data("level")-$(b).data("level")
});
}
function GenerateGdivList(){
var GdivList = $(".box");
GdivList.sort(function(a, b){
return $(a).data("gender")-$(b).data("gender")
});
}
As #theduke said, the lists are probably empty at the time you sort them. Here's a simple change that will read and sort the lists when you click the buttons instead. (Not tested.)
var LdivList = function () {
return $(".box").sort(function(a, b){
return $(a).data("level")-$(b).data("level")
});
};
var GdivList = function () {
return $(".box").sort(function(a, b){
return $(a).data("gender")-$(b).data("gender")
});
};
/* sort on button click */
$("button.LbtnSort").click(function() {
$("#sortThis").html(LdivList());
});
/* sort on button click */
$("button.GbtnSort").click(function() {
$("#sortThis").html(GdivList());
});

split ajax response in two different divs

I have an Ajax code like this:
$j(document).ready(function () {
function loading_show() {
$j('#loading').html("<img src='images/loading.gif'/>").fadeIn('fast');
}
function loading_hide() {
$j('#loading').fadeOut();
}
function loadData(page) {
loading_show();
$j.ajax({
type: "POST",
url: "load_data.php",
data: "page=" + page,
success: function (msg) {
var $response = $j(msg);
// Query the jQuery object for the values
oGlobal = $response.filter('#Z').text();
$j("#container").ajaxComplete(function(event, request, settings) {
loading_hide();
$j("#container").html(msg);
});
}
});
}
loadData(1); // For first time page load default results
$j('#container .pagination li.active').live('click', function () {
var page = $j(this).attr('p');
loadData(page);
});
});
Im getting this response:
<div id="container">
<div id="Z">JuanFernando</div>
<div id="q">
<div class="pagination">
<ul>
<li p="1" class="inactive">First</li>
<li class="inactive">Previous</li>
<li p="1" style="color:#fff;background-color:#006699;" class="active">1</li>
<li p="2" class="active">2</li>
<li p="2" class="active">Next</li>
<li p="2" class="active">Last</li>
</ul>
<input class="goto" size="1" style="margin-top:-1px;margin-left:60px;"
type="text">
<input id="go_btn" class="go_button" value="Go" type="button"><span class="total" a="2">Page <b>1</b> of <b>2</b></span>
</div>
</div>
</div>
I want to extract "JuanFernando" in order to show in div container but alone and I want that the rest of the response could be show in other different div for example: container2.
ajaxComplete is not what you want to use here, especially inside your success function. You want your success function to look something like this:
success: function (msg) {
loading_hide();
var $response = $j(msg);
// Query the jQuery object for the values
oGlobal = $response.find('#Z').text();
$j("#container").html(oGlobal);
$response.find('#Z').remove();
$j('<div id="container2"></div>').html($response.html()).appendTo('body');
}
We're just taking the oGlobal (which should be JuanFernando in this case) and sticking it in the #container. After that, remove the #Z div from the response, and stick the rest inside of a new #container2, and append it to the body, or wherever you'd like it.
Here's an "adapted" fiddle.
Basically the only thing that changes with you code is
replace
oGlobal = $response.filter('#Z').text();
with
oGlobal = $response.find('#Z').text();
also, see MattDiamant's answer concerning ajaxComplete.

JQuery Closest Method to change HTML

I am working on a project, i have two anchors in my View(for voting functionality),
I have a div inside which i am having a <ul> and in 3 <li> i am having anchor for upvote,vote count (in <h2>) and anchor downvote respectively
I want functionality that when i click on any anchor, the h2 html show the vote count, i've implemented the functionality but because of i am unable to do this,
this is my View
<div class="voting" style="margin-left:20px;">
<ul>
<li class="addvote"><a href="#" class="voteAnswer" answerid="#answer.AnswerID" name="Voted">
Up</a></li>
<li class="votecounter">
<h2>
#answer.AnswerLikes.Where(a => a.IsActive == true).Count()</h2>
</li>
<li class="subvote"><a href="#" class="voteAnswer" answerid="#answer.AnswerID" name="Voted">
Down</a></li>
</ul>
</div>
and this is my JS
$(".voteAnswer").click(function (event) {
var answerid = $(this).attr('answerid');
var name = $(this).attr('name');
var id = $(this).attr('id');
var output = $(this);
$.ajax({
url: ResourceAjaxUrl.VoteUnvoteTheAnswer,
type: "POST",
data: JSON.stringify({ answerID: answerid }),
dataType: "html",
contentType: "application/json; charset-utf-8",
success: function (Result) {
alert("Voted");
// $(output).html("Voted (" + Result + ")");
$(output).closest("li").find("h2").html(Result);
$(output).attr("name", "Voted");
},
error: function (msg) {
alert("Unable to Vote answer: " + msg);
}
});
event.preventDefault();
});
i have tried using $(output).closest("li").find(".votecounter") but its still not working
The UL is the closest common ancestor.
Try:
$(output).closest("UL").find(".votecounter")
there are some problems in your code .
here
$(".voteAnswer").click(function (event) {
var id = $(this).attr('id');
there is no attribute id in .voteAnswer
and also how do you differentiate upvote and downvote .
you have to check the anchor's parent li tag's class and check it is upvote or down vote .
also you can select the .votecounter
simply by
$(".votecounter").find("h2").html(Result);
or
$(output).closest("ul").find(".votecounter");

Categories