How to access dynamic content in list from setInterval - javascript

In javascript, On $(document).ready(function() I have a function updateRecordTime() run to update dates in list items (with nested divs), and I have a setInterval() run that function every 30 seconds to update, but after a dynamically add list items via ajax they are not updated also. I have the function running on a static element to look at an Unordered List for its list items but its not working and I can't figure it out.
updateRecordTime = function () {
$('#record-lister > li').each(function (index) {
var record_time = $(this).find('.record-time');
date = moment(new Date(record_time.attr('data-date')));
update = function () {
record_time.html('Record - ' + date.fromNow() + ' <i class="icon-time"></i>');
};
update();
});
}
updateRecordTime();
setInterval(updaterecordTime, 30000);
The html (relevant code) is as follows
<ul id="record-lister">
<li>
<div class="record-time" data-date="'.date('Y-m-d H:i:s', $timestamp).'">
gets replaced with moment time....
</div>
</li>
<li>
<div class="record-time" data-date="'.date('Y-m-d H:i:s', $timestamp).'">
gets replaced with moment time....
</div>
</li>
</ul>
If I call the function after a successful ajax call, it's updated once, but the loop doesn't find it, I'm aware setInterval() will loop the original list items but how can I get it to also find the dynamically added ones too?

As A.Wolf said, your code should find the newly inserted li tags.
Make sure you correctly populate the ul tag having id="record-lister". You can inspect the html code added dynamically to make sure of this.
Watch js errors from your browser console so that the code doesn't break at some point. I recommend you Firebug or Chrome Dev Tools.
When calling setInterval(funcName, interval), you must be aware that funcName is a pointer to your function and you must pay attention to function scopes. Calling setInterval("funcName()", interval) will call funcName from the global scope ( i.e. window.funcName ).
Based on the code given by you here, those are my advices, and it should work just fine assuming that adding html code via ajax works good.

Related

Options to make jQuery Ajax code more efficient / logical

I have the following HTML to display content pulled from an ajax script (ajax.php):
HTML
<ul class="list-unstyled" id="var_adjectives"><li><a href='#'>Loading...</a></li></ul>
<button id="37" onclick='update_adjectives();'>Refresh</button>
<hr />
<ul class="list-unstyled" id="var_brands"><li><a href='#'>Loading...</a></li></ul>
<button id="37" onclick='update_brands();'>Refresh</button>
<hr />
<ul class="list-unstyled" id="var_clothes"><li><a href='#'>Loading...</a></li></ul>
<button id="37" onclick='update_clothes();'>Refresh</button>
<hr />
When the page first loads, the following JS is used to populate the list items against the relevant <ul> tag (passing in two parameters each time):
Javascript Page Load
$(document).ready(function(){
$.post('ajax.php',{u:37,n:1} ,function(data){ var this_record = data.output; $('#var_adjectives').html(this_record);},'json');
$.post('ajax.php',{u:37,n:33},function(data){ var this_record = data.output; $('#var_brands').html(this_record);},'json');
$.post('ajax.php',{u:37,n:67},function(data){ var this_record = data.output; $('#var_clothes').html(this_record);},'json');
});
The refresh button can be used to refresh the content in the relevant <ul> tag, calling the following relevant JS function, from the onclick event on each of the 3 buttons:
Javascript Refresh Functions
function update_adjectives() {
$.post('ajax.php'
, {u:37,n:1}
, function(data){ var this_record = data.output; $('#var_adjectives').html(this_record); }
, 'json')
};
function update_brands() {
$.post('ajax.php'
, {u:37,n:33}
, function(data){ var this_record = data.output; $('#var_brands').html(this_record); }
, 'json')
};
function update_clothes() {
$.post('ajax.php'
, {u:37,n:67}
, function(data){ var this_record = data.output; $('#var_clothes').html(this_record); }
, 'json')
};
As you can see, there is a lot of overlap in the basic design of the JS.
I have these questions:
I am stuck working out how I can end up with one single line in the block of JS used to populate content when the page first loads.
I'd like to only have 1 function used to refresh content - because in my example above I have 3 blocks, but in my real page I have about 30 blocks.
While the JS is created by the PHP code when the page loads (rather than me writing it long-hand), it still would be nice to have much cleaner code which avoids having e.g. 30 refresh functions and 30 lines of code to populate each of the different <ul> IDs when first loading the page.
In each case, I can see I would need to pass an ID of relevant <ul> but I am tied up in knots working out if I can achieve what I'm trying to do.
Probably there are many things wrong with using the onclick event too!
Any advice would be much appreciated, thank you.
The most likely blocker is your API endpoint design. According to what you posted, you must access one category at a time and that must be done by sending the {u:N,n:N} combo object as the body of the POST request.
It would simplify things greatly if your endpoint accepted a different object. Something like {category:'name'} would allow greater flexibility.
You could use {category: 'all'} for the initial view of all categories and use {category: 'clothes'} for individual categories for the update/refresh.
Extending that to the click of the refresh buttons. You can use a single event handler and event bubbling to deal with every button click.
First you would add the event handler to containing element for all the <ul> elements.
Given this layout:
<div id='container'>
<ul><li><span>loading...</span></li></ul>
<button data-category="adjectives">Refresh</button>
<ul><li><span>loading...</span></li></ul>
<button data-category="brands">Refresh</button>
<ul><li><span>loading...</span></li></ul>
<button data-category="clothes">Refresh</button>
</div>
You can react to all the button clicks like this:
document.getElementById('container').addEventListener('click', update);
The update() event handler can determine which button was clicked by checking out the data- attribute on the button. Then, make the AJAX request and place the data into the correct <ul> by finding the closest or the prev() sibling <ul> element.
function update() {
const category = this.dataset.category;
$.post('ajax.php', {category: category}
, function(data) {
$('button').data(category).prev('ul').html(data.output);
}, 'json')
};

Select a subdiv with JS event listener

I'm trying to create a simple buzzfeed quiz with HTML and JavaScript as a practice project. All my options are divs of subdivs in HTML. The four options are a div, the top row of two options is a subdiv, and then each option is a subdiv under that. So my HTML looks like:
<div id="q1">
<p class="question">What's your favorite kind of bread?</p>
<!-- First set of options -->
<div class="optionsSet">
<!-- Sourdough -->
<div class="option" id="sourdough">
<img class="optionPic" src="/pictures/b-sour.jpg" alt="Sourdough" id="sourpic">
<p class="caption">Sourdough</p>
</div>
I can't get my JS event listener to grab onto anything. Instead it executes immediately upon loading the page no matter which event I'm trying to hone in on. Here's the latest that I think should be foolproof but it's not working:
var test = new function test() {
console.log("test succeeded");
}
document.getElementById('sourdough').addEventListener("mouseup", test)
Once I get this formatted and able to produce an output predictably and reliably I'll tinker with the actual outputs. For no,w I can't even get to that part!
var test = new function test() {
console.log("test succeeded");
}
You need to remove the new keyword before the function declaration.
new is used when you want to create a new object
Here is the working codesandbox.
Remove the "new" from your code and it should be fine.

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>

Show the item width an certain ID that is received by ajax

I have several content items on the page all of the are hidden and they have each a unique ID. #data serves as a temporary stack.
<div id="data"></div>
<div id="item1212">...</div>
<div id="item2323">...</div>
<div id="item3434">...</div>
<div id="item4545">...</div>
an Ajaxrequest gives me back a certain ID
$('#data').load('http://someURL');
fills the #data:
<div id="data">2323</div>
width this lines I make my correspondig item visible:
var theID = $('#data').text().val();
$('#item'+theID).toggleClass('visible');
This was my idea. Guess: Ist does not work cause it fails to read #data and use the value as a string. Its alwas an object (?).
I save the value first in html cause I dont know how to save a ajax-result (its always a string value) to a JS variable.
But I guess you have much better ideas how to solve my Problem: Show item width an certain ID that is receved by ajax
Your logic works fine (aside from the fact you don't need val()), you just need to execute it after the load() call completes as it is asynchronous. Currently you're trying to access the new content before it exists. To do that you can use the callback parameter, like this:
$('#data').load('http://someURL', function() {
var theID = $('#data').text();
$('#item' + theID).toggleClass('visible');
});

How to edit list item on another page

The Situation
In Sharepoint 2010 I can click on an item in a list:
And then the Read/Edit view becomes visible in that page:
My Goal
I have a WebPart on another Page where I show some items coming from this and several other lists and I want to add a read or edit link to each of them.
How can I do that?
I'm searching for a function like EditListItem('ItemId', 'ListId', ...) which will open the edit div window.
What have I tried
The a tag generated by Sharepoint on "Test Item" above is like this:
<a onfocus="OnLink(this)"
href="http://{mysharepointsite}/_layouts/listform.aspx
?PageType=4
&ListId={D0FDB54F-1DDF-4C5E-865B-ABDE55C1125}
&ID=1
&ContentTypeID=0x010800ED5176D13CCEFC4AA8D62A79985DE892"
onclick="EditLink2(this,49);return false;" target="_self">Test Item</a>
So I digged a bit into the Sharepoint JS files and found EditLink2 calling _EditLink2 which calls ShowPopup from the context (the 49) is the context no and seems to be dynamic.
I tried to fake the context but there are billions of variables and I think I can't get that to work stable.
On that page where you need to open dialog just write simple JS function for showing modal dialog, for example:
function openMyItemDialog( itemId ) {
var options = {
url: "http://{mysharepointsite}/_layouts/listform.aspx?PageType=4&ListId={D0FDB54F-1DDF-4C5E-865B-ABDE55C1125}&ID=" + itemId + "&ContentTypeID=0x010800ED5176D13CCEFC4AA8D62A79985DE892&IsDlg=1",
width: 500,
height: 500,
title: "Item view/edit"
};
SP.UI.ModalDialog.showModalDialog( options );
}
Note the &IsDlg=1 param at url
And then modify href link where you display your items.
For example:
Test item
Replace 35 to ID of your item
I know this is an old question, but there's another way to achieve what the OP was trying to do.
In a XSLT ViewWebPart, there is a global parameter named $ViewCounter.
This is the context number required by the _EditLink2 function.
So, in order to add a link to the display form and have it opened in a dialog, wrap the item in an <a> tag like this:
your item
Notice the variables $HttpVDir, $List, $thisNode/#ID and $ViewCounter (no need to hard-code any value).

Categories