Making HTML Bootstrap elements dynamic using JQuery + React? - javascript

I'm completely new to web development so please put up with me, haha.
Here's a brief description of what I'm trying to do:
Make a webpage in HTML, using Bootstrap, that displays lists of items (in the form of a group of Checkboxes, Labels, etc)
Using a combination of JQuery and React, make these elements dynamic.
Now here's a gist of how I'm currently trying to accomplish it.
Example list
<ul class="list-group" id="PortfolioListOfStocks" >
<li class="list-group-item" id="stockTicker0">1</li>
<li class="list-group-item" id="stockTicker1">2</li>
<li class="list-group-item" id="stockTicker2">3</li>
<li class="list-group-item" id="stockTicker3">4</li>
<li class="list-group-item" id="stockTicker4">5</li>
</ul>
I can statically access and edit a set number of these checkboxes (which are going to be tickers) with this react code. Tickers is just an array of Ticker objects, which are just being treated as strings right now:
render: function () {
for (var i=0; i < this.state.tickers.length; i++) {
document.getElementById("stockTicker"+i).innerHTML = this.state.tickers[i];
}
return null;
}
So I can edit and access the checkboxes, great! BUT the problem I'm having is how to start with 0 checkboxes, and only add in checkboxes when needed, and delete checkboxes when not needed, based on the length of the array. So when size = 3, just 3 elements, but when size = 15, a scrollable box of the 15.
I know I can use JQuery/JS to add checkboxes, which can easily be called. It would look something like this
$('#addCheckbox').click(function() {
var text = $('#newCheckText').val();
$('#cblist').append('<input type="checkbox" id = "changeThis" /> ' + text + '<br />');
});
But the problem with this is that I'm not able to create the elements with the Bootstrap format, the checkboxes aren't aligned (they look something like the image below), and the Bootstrap theme is not preserved. I tried to use CSS but it wasn't working out for me.
So overall takeaway, how do I make the number of items present based on the length of the array? I'm really just struggling with the interconnection between HTML and script. Thanks for reading!!

The following should work:
render: function () {
var tickerGroupItems = this.state.tickers.map(function(ticker){
return <li key={ticker.id} className='list-group-item' id={'stockTicker' + ticker.id}>{ticker.name}</li>
});
return(
<ul className="list-group" id="PortfolioListOfStocks" >
{tickerGroupItems}
</ul>
);
}

Related

How to dynamically get the dynamically created ID in a li

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>

how to select a div based on the data attribute that matches a variable?

I am trying to use Jquery ui tabs with salesforce communities, if a user is being directed from a different page to the current page, based on the project id of the previous page, the current page needs to highlight the appropriate tab.
These tabs are generated based on how many project a user
has which prevents me from giving them an ID inside the html
<script>
$(document).ready(function(){
var focusedProject = '{!focusedProjectId}';
$('.projectTabs').each(function(){
var id = $(this).data('salesforceprojectid');
if(focusedProject === id){
$('*[data-salesforceprojectid="HARD CODED ID"]').addClass('ui-state-active');
}
});
});
</script>
Where you see the words hard coded Id i want to put the variable focusedProject - it doesnt seem this is possible, does anyone know an alternate solution for this?
<ul>
<li class="projectTabs" data-salesforceprojectid="{!projectList.Id}"></li>
<li class="projectTabs" data-salesforceprojectid="{!projectList.Id}"></li>
<li class="projectTabs" data-salesforceprojectid="{!projectList.Id}"></li>
<li class="projectTabs" data-salesforceprojectid="{!projectList.Id}"></li>
</ul>
you can't do
$('*[data-salesforceprojectid="' + focusedProject + '"]').addClass('ui-state-active');
to make the hard coded part into a variable?

How do I generate these jQuery links inside of a <ul> element after the first <li> child element?

Hi, I'm having real trouble trying to solve this problem of mine. Although in my last 6-7 hours of despair I have come up with several viable options to make the problem go away, I haven't by any means been able to figure it out. I am trying to edit some source code (included) to achieve what the Title of this question suggests.
I am using the following jQuery plugin: jQuery Cycle Plugin - Pager Demo with Prev/Next Controls
What I am trying to get this to do with my own markup is generate the links that contain the <a> elements within the <li> elements come after and before the first and last <li> elements contained in the targeted parent element...(<ul>). Here's the plugins configuration:
$(function() {
$('.recent_slider').cycle({
fx: 'scrollHorz',
timeout: 0,
prev: '.slide_l',
next: '.slide_r',
pager: '.slide_nav',
pagerAnchorBuilder: pagerFactory
});
function pagerFactory(idx, slide) {
var s = idx > 4 ? ' style="display:none"' : '';
return '<li'+s+'>'+idx+'</li>';
};
});
Where pager: '.slide_nav', refers to the parent <ul> element, I have this plugin's next and previous controls being used as <li></li> (with slide_l meaning "slide left" / previous) and <li></li> (meaning "slide right" / next).
What I want to be able to do is insert the pager links generated from return <li'+s+'>'+idx+'</li> in between .slide_l and .slide_r so it appears something like:
<ul class="slide_nav">
<li></li>
<li'+s+'>'+idx+'</li>
<li'+s+'>'+idx+'</li>
<li'+s+'>'+idx+'</li>
<li></li>
</ul>
The issue is that is adds them after so in effect I get something along the lines of "previous","next", "slide1", "slide2", "slide 3" where as what I need is "previous","slide1", "slide2", "slide3", "next"...
Here's the plugin's almighty 1500+ lines of source code which together with the above configuration and markup containing the class names: .slide_nav, .slide_l and slide_rwill cause the headache I'm having...
Please help.
Since you want to change how the UI is displayed, and not the structure of the content, CSS would be a better way to solve this.
Change your html to this:
<span class="slide_l">Prev</span>
<ul class="slide_nav"></ul>
<span class="slide_r">Next</span>
And add this CSS (note this is just a starting point, add onto it to make it look nice):
.slide_nav, .slide_nav li, .slide_l, .slide_r {
display: inline-block;
margin: 0;
padding: 0;
}
The CSS makes all the elements flow horizontally (using display: inline-block) to make it similar to a standard paginator.
Fiddle: http://jsfiddle.net/dwx1v9c7/1/
You could also get the html of the .slide_nav and then mess with it as a string.
var x = $('.slide_nav').html();
var arr=x.split('</li>');
var mystr = '';
for (var r=0, len=arr.length; r<len; r++) {
mystr += arr[r];
if (r===0) {
//your code to add additional LI's
}
}
$('.slide_nav').html(mystr)
It's far from the most elegant solution but it should work.

Separating & cleaning up tags in data-attribute via jQuery

I have a list of items which will contain a tag using the data-type attribute. I'm attempting to loop through the items to grab each tag in an array. Where a list item has more than one tag (separated by a comma) I want to split the tags and clean up any white-space.
Here is my HTML:
<div class="article-wrap">
<ul class="articles">
<li sata-type="tag3"> LTE opens vast new business and revenue opportunities. Here's how to get ready.
</li>
<li data-type="tag3"> Bringing NFC into the Digital Home
</li>
<li data-type="tag3, tag4"> Keep Up with Rapidly-changing Wi-Fi Standards, Techniques and Markets
</li>
<li data-type="tag1"> Technicolor Professional Services help NSPs reduce software vulnerability
</li>
<li data-type="tag2, tag3"> Our New Satellite/terrestrial HD Set-top Box Provides a Smooth Path to HDTV.
</li>
</ul>
</div>
And here is my JS:
$(function () {
var items = $('.article-wrap li'),
itemsByTags = {};
// Looping though all the li items:
items.each(function (i) {
var elem = $(this),
tags = elem.data('type').split(',');
// Adding a data-id attribute
elem.attr('data-id', i);
$.each(tags, function (key, value) {
// Removing extra whitespace:
value = $.trim(value);
if (!(value in itemsByTags)) {
// Create an empty array to hold this item:
itemsByTags[value] = [];
}
// Each item is added to one array per tag:
itemsByTags[value].push(elem);
});
});
});
I believe this should be working fine, alas I get Uncaught TypeError: Cannot call method 'split' of undefined. You can see this here: http://jsfiddle.net/94UUF/2/
I can use the same items var to amend CSS etc but the .split function doesn't seem to want to play ball. Please advise!
Did you notice:
<li sata-type="tag3">
Is sata instead of data hence the error:
Uncaught TypeError: Cannot call method 'split' of undefined.
You can actually embed object literals in data tags. So if you do data-type='["tag3”, ”tag4”]' then .data('type') will return an array.

Append and remove values in a link

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

Categories