I've been trying to learn js (and a tad of jquery) and I have run into two difficulties when trying to find a way to combine solutions that I find.
Just a little warning that this code is a mix of a few tutorials that I have recently done. I am very new to js.
So I start with a basic html with a few li.
<body>
<ol id="liste">
<li class="active">
</li>
<li>
</li>
<li>
</li>
</ol>
<div id="main_ima">
</div>
<script src="js/main.js"></script>
</body>
I want to create ids for each "li" so in my main.js I add this:
var idVar = $("#liste").find("li").each(function(index){
$(this).attr("id","num-li-"+index);
});
This works great so far. Everytime I add a new li, it gets a new id. I also put it into a var because I will need to use it later.
In th console, If I type idVar, it gives me the whole list of li. If I type idVar[3]. it only gives me the li associated to the [3]. Perfect.
Now I want to get something to appear when one of the li is clicked. For example, I will use the [3]. So I add this to my main.js
var imaContainer = document.getElementById('main_ima')
var listed = document.getElementById('liste');
idVar[3].addEventListener("click", appar);
function appar(){
$(idVar[3]).addClass("active").siblings().removeClass("active");
var imaSel = new XMLHttpRequest();
imaSel.open('GET', 'https://domain.link.to.file.json');
imaSel.onload = function() {
var imaLo = JSON.parse(imaSel.responseText);
renderHTML(imaLo);
};
imaSel.send();
};
function renderHTML(data) {
var htmlS = "";
for (i = 0; i < data.length; i++) {
htmlS += "<p>" + data[i].name + " is a " + data[i].species + ".</p>";
}
imaContainer.insertAdjacentHTML('beforeend', htmlS);
}
Just a side note, I added the add/remove "active" class for CSS.
So when I click the li[3], it works almost as expected. The only thing is when I reclick [3] it produces the result a 2nd time. And again, if I click it a 3rd time, it produces the result a 3rd time, without remove the past results. (which is not totally what I want. Just the 1st result would be better.)
But that is not the main problem I am facing.
I would like the [number] to be dynamically detected, based on the id of the clicked li. I could, in a very ugly way, copy and past this code for every [number] I have. and it would work. But then, what if I want to add more li elements, I would need to add more copy and paste of the above code, giving me possibly huge files for nothing. This is surely not the best way, although it would work.
I'm sure this can be done dynamically.. but that is mostly why I am here. :)
Afterwards, once the dynamic has been added to the clicked li, I would also like the link to be changed dynamically based on the li id. For example, instead of :
imaSel.open('GET', 'https://domain.link.to.file.json');
something like:
imaSel.open('GET', "https://domain.link.to.file" + var +".json");
the var being equal to the [3] number of the clicked li.
In this case, when I try to add a var with a for loop, I always get the "var = max.length" instead of the "var = [id of clicked item]".
So there you have it. Do you need more details?
This is my first JS and/or Jquery try. I've been playing with it for a few days but when I search for answers, when I implement the "solutions" it alwas gives me some new problem. So I am showing you the code that is the closest, IMO, to what I am looking for.
Hopefully, I am not too far away of somehting that works and is not as big as my solutions. :)
Thanks for your time and all help is appreciated.
Here are some suggestions:
You don't need to assign id attributes to your li. You actually never need that id. This will work just as well (note also the > in the selector which makes the find call unnecessary):
var $li = $("#liste > li");
Already now you can address each of the li as $li[3], although that is not the "best practise". Better is $li.get(3). I also like the convention to start the variable with $ when it is the result of a jQuery selection. It gives a clue that you can apply jQuery methods to it.
You don't need to assign a click handler to each li separately. With jQuery on (instead of the native addEventListener) you can assign one event handler for all of them at once.
$li.on('click', apar)
The callback you define for on will have this set to the particular li element that has been clicked, so you can do:
$(this).addClass("active").siblings().removeClass("active");
... without any array lookup.
jQuery offers easy functions for several types of HTTP requests, so you don't need to use XMLHttpRequest. In fact, there is one specifically for getting JSON, so you don't even have to parse the response:
$.getJSON('https://domain.link.to.file.json', renderHTML);
The jQuery index() method can give you the sequence number of that li:
$.getJSON('https://domain.link.to.file' + $(this).index() + '.json', renderHTML);
To replace the inner HTML of a certain element, the jQuery html method can be used:
$('#main_ima').html(htmlS);
Note also how you don't need the DOM native getElementById method, jQuery can look that up for you with the short $('#main_ima').
Example
Here is a working example with a fake JSON serving server:
$("#liste > li").on('click', apar);
function apar() {
$(this).addClass("active").siblings().removeClass("active");
$.getJSON('https://jsonplaceholder.typicode.com/posts/'
+ (1+$(this).index()), renderHTML);
}
function renderHTML(data) {
// This particular JSON request returns an object with body property
var htmlS = data.body;
$('#main_ima').html(htmlS);
}
// On page load, click on the first `li` to automatically load the data for it
$('#liste > li:first').click();
#liste { width: 40px }
.active { background: yellow }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol id="liste">
<li class="active">load 1</li>
<li>load 2</li>
<li>load 3</li>
</ol>
<div id="main_ima"></div>
The following answers your main concern, how to dynamically get the ID with jquery:
$('.listen-to-me').click(function() { //Add event listener to class
var elementId = $(this).attr('id'); //Get the 'id' attribute of the element clicked
var idNumber = elementId.substring(elementId.indexOf("-") +1); //Get the index of the "-" in the string, and then cut everything prior
alert(idNumber); //The final result
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li id="test-1" class="listen-to-me">1</li>
<li id="test-2" class="listen-to-me">2</li>
<li id="test-3" class="listen-to-me">3</li>
<li id="test-4" class="listen-to-me">4</li>
<li id="test-5" class="listen-to-me">5</li>
</ul>
Related
For my school's website they have a dropdown list of courses that you're currently enrolled in on the home page. However, if you see it, it is cluttered full of letters that many people might not want to see.
I already know how I'm going to do this. I'm going to use jQuery to select each list item:
var links = $(".d2l-datalist li .d2l-course-selector-item .d2l-left .vui-link");
This returns an array of <a> elements in text form.
Using links.text("Boo!"); I can set the text of all of them to "Boo!", but I want to change each one individually, using a for/in loop to itterate through each <a> and change the text depending on what the value of the href is.
However, whenever I do this, since the items in the array are strings, I cannot do anything to them with jQuery.
Any help with this is appreciated :)
Here's my code so far (running from a $.getScript() from a JS bookmarklet):
var links = $(".d2l-datalist li .d2l-course-selector-item .d2l-left .vui-link");
//links.text("Boo!");
var count = 1;
for (var link in links) {
link.text("Boo #" + count);
count += 1;
}
Relevant markup: http://hastebin.com/ulijefiqaz.scala
You can use the jQuery .each iterator function.
var links = $(".d2l-datalist li .d2l-course-selector-item .d2l-left .vui-link");
var count = 1;
links.each(function() {
$(this).text("Boo #" + count++);
});
Trying to create a new list element every time a key press is detected. Originally I had this written down--
<ul class='text-box'> <strong>THIS IS SPARTA</strong>
</ul>
<script>
keycheck = 0;
$(document).keydown(function()
{
$('.text-box').text('Number of keypress are: '+keycheck);
keycheck=keycheck+1;
$('<p>').text(keycheck).appendTo('.text-box');
});
</script>
but this only created TWO line on keypress that updated with the number of clicks.
BUT removing the line "$('.text-box').text('hello '+keycheck);" gives me what I want.
I would like like to know why it did that, since I just started learning js I feel this would be something valuable.
If you do
$('.text-box').text('Number of keypress are: '+keycheck);
you replace all of the contents of .text-box with the given text. And "all of the contents" include the content that was added last time!
So you need append(...) instead of text(...). That's it.
However, if you want to make a list, you should use list items (<li>), not plain text and <p>. A better solution looks like this:
keycheck = 0;
$(document).keydown(function() {
$('.text-box').append('<li>Number of keypresses are: ' + keycheck + '</li>');
keycheck = keycheck + 1;
$('<li>').text(keycheck).appendTo('.text-box');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class='text-box'>
<li>THIS IS SPARTA</li>
</ul>
I'm using Ajax to retrieve data and populate my list. But I'm not able to get jQuery Mobile to add the classes needed to style my list, or refresh the list
if I do a new search (old results is still in list).
I've found plenty of similar Q/A's here on Stack, but none of the solutions work. I've not implemented the entire solution found over at jQuery Mobile, but I believe this should work anyway?
Am I building the list wrong? I have a fiddle here
// HTML
<ul id="brandList" class="front" data-role="listview" data-inset="true"></ul>
// JS
var el = Part.mainSearchResult();
$(response.brands).each(function(){
var brand = $(this)[0];
var url = '/brand?id=' + brand.id;
var li = $(el.brand).clone();
$(li).find('a').prop('href',url);
$(li).find('a').text(brand.name);
$('#brandList').append(li);
});
$('#brandList').listview('refresh');
$('#brandList').trigger( "updatelayout");
The code in your Fiddle had a mistake, you had the UL in the CSS section.
Was in the CSS Section, not HTML:
<ul id="mylist" class="front" data-role="listview" data-inset="true"></ul>
Seems to be working and is adding the classes to the UL.
Updated JS Fiddle
EDIT:
You need to call $('#mylist').listview( "refresh" ); inside the test function
NEW FIDDLE
So I am using http://isotope.metafizzy.co to filter out different items on a site. The menu should be a "build up" type where when one category is clicked, it filters to those categories, when the next is clicked it adds those newly clicked categories to the existing filter of categories. When its clicked a second time it should remove that categorie from the filter.
More specifically, I have href with #filter and data-filter=".category-name" I need to have a function that would add ", .another-category" to the end of data-filter value for each of the links with name="filters" (or i can use a class instead of if easier)
<ul>
<li>Kitchens</li>
<li>Bathrooms</li>
<li>Living Rooms</li>
<li>Bedrooms</li>
</ul>
I know this function is wrong and doesnt work but its just some pseudo-code
function addFilter(filter) {
names = document.getElementsByName("filters");
for (var name in names) {
name.data-filter = "existing filter, " + filter; // this should be appended to all data-filters
}
}
so basically when a link is clicked it both filters to that category only (lets say kitchens), but also adds the category to the rest of the data-filters (.bedrooms, .kitchens)
javascript or jquery or anything else i may have not realized could work. the documentation for isotope has the option to filter multiple groups of items, but I need it to filter combinations of individual items. Maybe its possible to modify their combination filters to items instead of groups?
See the following article as placed in this post. It should put you in the right direction.
http://www.queness.com/post/7050/8-jquery-methods-you-need-to-know
Stackoverflow question
jQuery - How to add HTML 5 data attributes into the DOM
Well you tagged jQuery, which makes this easy, but I only see you using JS. Anyway, here's one way and some extra info, hope it helps:
jsFiddle {with replication}
jsFiddle {without}
Script
$('li a[name="filters"]').on("click", function(e) {
e.preventDefault();
$(this).data("filter", $(this).data("filter") + ".another-category");
/* and if i wanted to do it without replicating already existing info:
var f = $(this).data("filter");
if (f.indexOf(".another-category") == -1) f += ".another-category";
$(this).data("filter", f); */
});
HTML
<ul>
<li>Kitchens</li>
<li>Bathrooms</li>
<li>Living Rooms</li>
<li>Bedrooms</li>
</ul>
X-tra NFO
jQuery.data(): Biggest Deference - Returns the value that was set
jQuery's .data(): Biggest Deference - Returns the element that was manipulated
i have below function which is being used to initialize a widget.
jQuery.fn.initPortlet = function( parent_component ,header , component ){
var o = $(this[0])
this.addClass("ui-widget ui-widget-content ui-corner-all")
.find(header)
.addClass("headertitle")
.addClass("align_center")
.addClass("defaultheadercolor")
.prepend('<span class="ui-icon ui-icon-minusthick"></span>')
.end()
.find(component);
};
what it does is append a minus icon at the top left corner of the widget.
i have some ajax call because of that this function get called multiple time and append a minus icon multiple times.
i am tring to re-write this function in such a way, so that how many time it's get called, append only one minus icon into header.
i tried fallowing approach but it didn't work.
var $minusthick = $('span.ui-icon ui-icon-minusthick');
$('div.div_header').find($minusthick).remove().prepend('<span class="ui-icon ui-icon-minusthick"></span>').end();
what i am tring is remove all span with class name span.ui-icon ui-icon-minusthick and finally append a minus icon, but it's not worked for me.
Edit
i am calling this function in this way-
$('.div_portlet').initPortlet('.div_portlet','.div_header','.div_content')
$('.div_portlet_inner').initPortlet('.div_portlet_inner','.div_header_inner','.div_content_inner');
html corresponding to this is-
html:
<div class="div_portlet" id="LINEITEM_HEADER" >
<div class="div_header"><%=hu.getFrameURL(82,83)%> Line Item Header Information</div>
<div class="div_content" id="LINEITEM_HEADER_CONTENT">
</div>
</div>
for second call html will remain same just classes will get change from div_portlet to div_portlet_inner, in the same way for other class.
i have written this function in a js file.
any help or suggestion so that i can achieve my goal will be highly appreciated.
Please guys help me out i got stuck at this point.
Thanks in advance!!!!!
Not sure what variable o is being used for - but the general point of my alteration below is to check to see if the class has been applied already, using the jQuery hasClass() function.
jQuery.fn.initPortlet = function( parent_component ,header , component ){
var o = $(this[0])
if (!this.hasClass('ui-widget'))
{
this.addClass("ui-widget ui-widget-content ui-corner-all")
.find(header)
.addClass("headertitle")
.addClass("align_center")
.addClass("defaultheadercolor")
.prepend('<span class="ui-icon ui-icon-minusthick"></span>')
.end()
.find(component);
}
};
ʞɔɐɯɹoↃɔW sǝɯɐſ gave a good solution to this problem, but here is an explanation why your attempt didn't work:
The first part of the selector 'span.ui-icon ui-icon-minusthick' is looking for a span with class ui-icon, as you intended, but the second part looks for an element of type <ui-icon-minusthick> which obviously doesn't exist. To select an element with multiple class names, add them all to the same selector just like you would in CSS:
$('span.ui-icon.ui-icon-minusthick')
Of course, the rest of you code would be a no-op since find($minusthick) will do nothing and therefore the rest of the jQuery chain will have no context in which to operate. This would (I think) work as you expected:
$('div.div_header').find('span.ui-icon.ui-icon-minusthick').remove().end().prepend('<span class="ui-icon ui-icon-minusthick"></span>');
The extra end() call returns the jQuery object to the first selector, in this case div.div_header and there is no need for the final end().