I'm working on a Business Catalyst site (Adobe). I need to insert a placeholder div after each row of items which another script later appends info to. This is working fine on most browsers but does nothing on IE 11.
The script looks for the last item in a row to insertAfter, ie. rows contain 4 items but if the last row only has 1 or 2 it inserts it after the last one.
I was using Jquery 1.1 but just switched to 1.7 and it seems to make no difference.
My markup:
<div class="roller col-md-3" id="roller001">
<div class="roller-type">
<div class="roller-image">
{tag_small image_nolink}
</div>
<a class="roller-btn" onclick="appendRoller{tag_itemid}('{tag_itemid}')" href="javascript:void(0);">{tag_name_nolink}</a>
</div>
</div>
<div class="roller col-md-3" id="roller002">
<div class="roller-type">
<div class="roller-image">
{tag_small image_nolink}
</div>
<a class="roller-btn" onclick="appendRoller{tag_itemid}('{tag_itemid}')" href="javascript:void(0);">{tag_name_nolink}</a>
</div>
</div>
Script:
<script type="text/javascript">
$(document).ready(function(){
var rollerItems = document.getElementsByClassName('roller');
for (n=0; n<rollerItems.length; n++) {
if(n%4 == 0) {
var rowEnd = rollerItems[n];
if(document.contains(rollerItems[n+1])) { rowEnd = rollerItems[n+1]; }
if(document.contains(rollerItems[n+2])) { rowEnd = rollerItems[n+2]; }
if(document.contains(rollerItems[n+3])) { rowEnd = rollerItems[n+3]; }
$('<div class="popup-row"></div>').insertAfter(rowEnd);
}
}
});
</script>
I've realised the problem was not with the 'insertAfter' command at all but with 'document.contains'. Apparently IE does not regard 'document' as a node and I needed to use 'document.body.contains' to determine items at the end of the row.
Eg.
if(document.body.contains(rollerItems[n+1])) { rowEnd =
rollerItems[n+1]; }
Went through everything line by line but glossed over that! Not sure if this is the best solution but it works now at least.
Related
I am retrieving an AJAX dump from a Django python Function.
Then, I am trying to reflect the data on a bootstrap row + column table.
However, when using append() in an array list, I only seem to get the first row of the dump. When I remove the 2nd for loop, the dump works fine, just does not give me the rows of the months that I need.
I have more than one row worth of data, definitely.
What could be causing this?
//html code
<div id="category_filtered_list">
<div class="row report_row mockup" id="category_mockup">
<div class="col-md-1 name"></div>
<div class="col-md-1 code"></div>
<div class="col-md-1 forecasted"></div>
<div class="col-md-1 running_total"></div>
<div class="monthsRows" id="monthsRows"></div>
</div>
</div>
//Ajax JS function
$.post(
"",
{
"getcategories": true,
'date-from': date_from,
'date-to': date_to
},
function(response) {
$("#category_filtered_list .report_row.product").remove()
data = JSON.parse(response);
for (var i=0; i<data.length;i++){
obj = data[i]
var mockup = $('#category_mockup')
var temp_mockup = $(mockup).clone()
$("#category_filtered_list").append(temp_mockup)
$(mockup).attr('id',"temp_product");
var temp_prod = $("#temp_product")
$(temp_prod).find('.name').html(obj.category_name)
$(temp_prod).find('.code').html(obj.category_code)
$(temp_prod).find('.minor').html(obj.category_minor)
$(temp_prod).find('.parent').html(obj.category_parent)
$(temp_prod).find('.forecasted').html(obj.category_forecasted)
$(temp_prod).find('.running_total').html(obj.products_count)
//this for loop is causing the issue ******* when removed, the rest of the code works fine. Please note that obj.prods_num_per_month is an array
for (i=0; i<=obj.prods_num_per_month.length; i++){
$(temp_prod).find('.monthsRows').append(
$('<div class="col-xs-1">').html(obj.prods_num_per_month[i])
);
}
$(temp_prod).removeClass('mockup');
$(temp_prod).addClass('product');
$(temp_prod).attr('id','')
}
}
).done(function(){
$("#filtering .message_loading").html("Completed! <i class='far fa-smile text-success'></i>")
$("#filtering .message_loading").addClass("fading")
$("#export_button").show()
setTimeout(function(){ $("#filtering .message_loading").html('') }, 5000);
});
I am expecting to get all rows with relevant data, but instead, I am just getting the first row.
Not my proudest moment... So.. The code works fine actually, but I have declared 'i' as the index for both 'for' loops, causing the main loop to terminate early..
I changed the index for the 2nd for loop and it's up and running as intended.
2 hours of debugging...Really not my proudest moment. Good news is it's fixed!
could some one tell me, how to update accordion datas with new values on button click as when user enter their input?
assume like there is input box. user hit submit after giving value. at the same time it should show the input what user gives in side accordion.
accordion ll be categorized as
/Latest update
/old updates
/etc
what am having is
$("className").click(function(){
setInterval(function(){
}, 900);
})
<div classname="className"></div>
it would be better if share fiddle/plunker snippets for Typescript, Jquery or even Angular2
many thanks for any help
because i had some free time i made you an example of what i think you want.
1.enter 'aa' the latest updates will slideDown and have text 'aa'
2.enter second value 'bb' the latest updates will have text 'bb' , old updates will have text 'aa' and also 'aa' is archived
3.enter third value 'cc' the latest updates will have text 'cc', old updates will have text 'bb' and archive will have 'aa' and 'bb'
and so on.
this is made using IF conditions which are very straight forward using text().length.
also included ( at the beginning of the JQ ) a simple accordion code
let me know if this is what you were looking for. check snippet below or jsFiddle
var accTrigger = $('h2')
$(".text").hide()
$("h2").on("click", function() {
var text = $(this).siblings(".text")
if ($(text).is(":visible")) {
$(text).slideUp()
} else {
$(text).slideDown()
}
$(this).parents(".accordion-item").siblings().find(".text").slideUp()
});
var button = $("button"),
input = $("input"),
latest = $("#latest .text"),
old = $("#old .text"),
archive = $("#archive .text")
$(button).on("click", function() {
inputValue = $(input).val()
if ($(latest).text().length > 0) {
$(old).text($(latest).text()).slideDown()
}
if ($(old).text().length > 0) {
var aText = $(archive).html()
$(archive).html(aText + '<br>' + $(old).text()).slideDown()
}
$(latest).text(inputValue).slideDown()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="accordion">
<div class="accordion-item" id="latest">
<h2>Latest Updates</h2>
<div class="text"></div>
</div>
<div class="accordion-item" id="old">
<h2>Old Updates</h2>
<div class="text"></div>
</div>
<div class="accordion-item" id="archive">
<h2>Archive</h2>
<div class="text"></div>
</div>
</div>
<input type="text" value="">
<button type="submit">
submit value
</button>
Currently matching a specific keyword using contains(). How can i expand this to include multiple keywords?
have tried using the || (or) operator, but no joy.
<!-- Product names include Apple iPad, Acer Iconia, Lenovo Thinkpad -->
<h1 id="pbtitle">Apple iPad 3</h1>
<div class="install_option" style="display:none;">
<div style="box-sizing:border-box; float:left;">
<a href="https://www.exmaple.com/acc" target="_blank">
<h3 style="font-weight:bold;">Would you like to view accessories?</h3>
</a>
</div>
</div>
$(".install_option").each(function() {
if($("h1#pbtitle:contains:contains('Acer' || 'Lenovo' || Apple )").length>0){
$('.install_option').css('display','block');
}
});
Use JavaScript function indexOf()
Working example jsfiddle
var options = ['Acer','Lenovo','Apple']; // options that you want to look for
var text = $("#pbtitle").text(); // string where you want to look in
options.forEach( function( element ) {
if ( text.indexOf( element ) != -1 ) { // if its NOT -1 (-1 = not found)
alert( 'found' ); // then we found it .. do your magic
}
})
Do this way
if($("h1#pbtitle:contains('Acer'),h1#pbtitle:contains('Lenovo'),h1#pbtitle:contains('Apple')").length>0)
Risking being a bit out of the question scope, I guess the product list is dynamic in same kind.
In that case it will be better to add a property to the product tag like:
<h1 id="pbtitle" has_install_option="true">Apple iPad 3</h1>
var condition = $('h1#pbtitle').attr('has_install_option') == 'true';
and checking that condition in your loop.
[think of the day you will have an Apple product with install_option or an Appleseed product...]
p.s in this example it's better to place the condition out side of the loop as the condition is static in relation to the looped elements
I have a page with a very large table (several thousand rows).
The table shows a subset of data specified by certain filters. I need the table to update whenever one of the filters changes.
Basically, there are a few check boxes and a text box, whenever one of these changes I reload the table to display only those rows which fit the criteria specified by the user.
I'm doing this by clearing the table and reloading the rows that match the filters. This works but has proven to be very slow.
Here is my javascript code:
function reloadTable() {
var tablebody = document.getElementById("tablebody");
while(tablebody.hasChildNodes()) tablebody.removeChild(tablebody.firstChild);
filter = new FilterChecker();
for (var i=0;i<rows.length;i++) {
if (filter.isVisible(rows[i]))
addRowToTable(rows[i]);
}
}
Is there a way to make it faster?
Alright, sorry for the delay, but I got wrapped up in work. I came up with a nice set of logic that illustrates what you need.
FIDDLE
I created some simple html to illustrate the point. It contains two drop downs to mimic the filters and 8 data rows to mimic your data grid.
<div id="body">
<select id="filterA" class="filter" name="states">
<option value="filterACT">Connecticut</option>
<option value = "filterAMA">Mass</option>
</select>
<select id="filterB" class="filter" name="towns">
<option value="filterBBT">Big Town</option>
<option value = "filterBST">Small Town</option>
</select>
<div id="grid">
<div class="row filterACT filterBBT">BigTown CT 1</div>
<div class="row filterACT filterBBT">BigTown CT 2</div>
<div class="row filterACT filterBST">SmallTown CT 1</div>
<div class="row filterACT filterBST">SmallTown CT 2</div>
<div class="row filterAMA filterBBT">BigTown MA 1</div>
<div class="row filterAMA filterBBT">BigTown MA 2</div>
<div class="row filterAMA filterBST">SmallTown MA 1</div>
<div class="row filterAMA filterBST">SmallTown MA 2</div>
</div>
</div>
</br>
<hr/>
<div>LOG</div>
<hr/>
<div id="log"></div>
The log div is simply to show an output, which I think would be helpful. Each row is identified by class 'row' followed by another series of classes. These classes help determine what their filter data is. You would need to set this programmatically when building the grid. Additionally, these class names must match the filter option values. You can see that the first row has classes from the first option in filterA and from the first option in filterB.
Now, the javascript is a bit verbose, but you can refactor to your hearts content. Sometimes I find it easier when things are explicit when you are trying to understand them. Also, admittedly, I would do this with jQuery, so my pure Javascript isn't as sharp.
var elements = document.getElementsByClassName('filter');
writeToLog("Filter elements found: " + elements.length);
for(var e = 0;e < elements.length;e++)
{
elements[e].onchange =function() {
writeToLog('Filter event fired for id:'+this.id);
filterChange();
};
}
First I get all the elements with the filter class, this would be your filters. I then iterate over them and set their onchange event to call the filterChange() method. The writeToLog() method calls are just for output purposes.
function filterChange() {
var filterClasses = [];
for(var i = 0;i<elements.length;i++) {
writeToLog('Pushing ('+elements[i].value+') into filter class variable.');
filterClasses.push(elements[i].value);
}
In the first part of the function I get all the select filter option values and put them into an array.
writeToLog('Filter classes: ' + filterClasses);
var rows = document.getElementsByClassName('row')
writeToLog('Row count: ' + rows.length);
I then get all of the rows, in my grid and start to iterate over them:
for(var j = 0;j<rows.length;j++)
{
writeToLog('Checking row: ' + rows[j].className);
var rowIsHidden = false;
Once I have a row, in the loop, I iterate the filter classes in the array and see if this row's classes have it. If not, I set rowIsHidden to true, otherwise it stays false.
for(var k = 0;k<filterClasses.length;k++)
{
writeToLog('Checking for class: ' + filterClasses[k]);
if(rows[j].className.indexOf(filterClasses[k]) < 0)
{
writeToLog('Class not found, hide this row.');
rowIsHidden = true;
break;
}
}
Before the loop moves to the next row, I set the display style based on the rowIsHidden value.
writeToLog('Row is hidden: ' + rowIsHidden);
rows[j].style.display = rowIsHidden ? 'none' : 'block';
}
}
By all means, this can be cleaned up and certainly optimized, but I think the intent and logic is fairly clear. Hope this helps and feel free to question any of it :)
I have a div, #containerDiv, which contains elements related to users like first name, last name etc. in separate divs. I need to sort the contents of the container div based on the last name, first name etc. values.
On searching google the examples I got all are appending the sorted results and not changing the entire HTML being displayed. They are also not sorting by specific fields (first name, last name).
So please help me in sorting the entire content of #containerDiv based on specific fields and also displaying it.
The Page looks Like something as mentioned Below:
<div id="containerDiv">
<div id="lName_1">dsaf</div><div id="fName_1">grad</div>
<div id="lName_2">sdaf</div><div id="fName_2">radg</div>
<div id="lName_3">asdf</div><div id="fName_3">drag</div>
<div id="lName_4">fasd</div><div id="fName_4">gard</div>
<div id="lName_5">dasf</div><div id="fName_5">grda</div>
<div id="lName_6">asfd</div><div id="fName_6">drga</div>
</div>
On getting sorted by last name div values, the resulted structure of the container div should look like:
<div id="containerDiv">
<div id="lName_3">asdf</div><div id="fName_3">drag</div>
<div id="lName_6">asfd</div><div id="fName_6">drga</div>
<div id="lName_5">dasf</div><div id="fName_5">grda</div>
<div id="lName_1">dsaf</div><div id="fName_1">grad</div>
<div id="lName_4">fasd</div><div id="fName_4">gard</div>
<div id="lName_2">sdaf</div><div id="fName_2">radg</div>
</div>
Now I think you all can help me in a better way.
this is a sample example:
html:
<div id="containerDiv">
<div>2</div>
<div>3</div>
<div>1</div>
</div>
js
$(function() {
var container, divs;
divs = $("#containerDiv>div").clone();
container = $("#containerDiv");
divs.sort(function(divX, divY) {
return divX.innerHTML > divY.innerHTML;
});
container.empty();
divs.appendTo(container);
});
you may set your divs.sort function param depend on your goal.
jsFiddle.
and a jQuery Plugin is suitable
I suggest you read the div values so you get an array of objects (persons for example) or just names and perform a sort operation on that. Than...output the result to the initial div (overwriting the default values).
I have built a jQuery sort function in which you can affect the sort field.
(it rebuilds the html by moving the row to another location).
function sortTableJquery()
{
var tbl =$("#tbl tr");
var store = [];
var sortElementIndex = parseFloat($.data(document.body, "sortElement"));
for (var i = 0, len = $(tbl).length; i < len; i++)
{
var rowDom = $(tbl).eq(i);
var rowData = $.trim($("td",$(rowDom)).eq(sortElementIndex).text());
store.push([rowData, rowDom]);
}
store.sort(function (x, y)
{
if (x[0].toLowerCase() == y[0].toLowerCase()) return 0;
if (x[0].toLowerCase() < y[0].toLowerCase()) return -1 * parseFloat($.data(document.body, "sortDir"));
else return 1 * parseFloat($.data(document.body, "sortDir"));
});
for (var i = 0, len = store.length; i < len; i++)
{
$("#tbl").append(store[i][1]);
}
store = null;
}
Every time I need to sort lists I use ListJs.
It's well documented, has good performance even for large lists and it's very lightweight (7KB, despite being library agnostic).