How to run a function after an external JS script finishes running - javascript

I am trying to understand how to ensure my code runs after an external JS file has finished running.
If you need a specific implementation, you can look at this SO question, which I am trying to help answer: How to get the last table row no matter the sort?
TDLR: The script found in bootstrap-sortable.js runs a table sort. After this table sort is complete; I want to make it so that I can run a snippet, which will add a simple CSS class to the last element in the freshly sorted table. The adding of the class can easily be achieved by this JQuery snippet:
var lastRow = $(this).closest("table").find("tbody tr:last");
if(!lastRow.hasClass("dropup")){
// Removing dropup class from the row which owned it
$(this).closest("table").find("tbody tr.dropup").removeClass("dropup");
// Adding dropup class to the current last row
lastRow.addClass("dropup");
}
I would like to know:
Is it possible to run my script after the external script is done running?
If not, can you explain why?
I have already considering modifying bootstrap-sortable.js to add my script to it, is this the best recommendable approach?
Bonus round! (only if you feel you need the challenge).
Is there a better, do-it-yourself, solution for sorting the table other than using bootstrap-sortable.js for the linked question?
Thanks everyone!

I want to thank Dave Newton for leading me to the answer to this question which is quite simple.
JSFiddle
$(document).ready(function() {
$("#MyTable").on('sorted', function(){
var lastRow = $("#MyTable").find("tbody tr:last");
// Removing dropup class from the row which owned it
$("#MyTable").find("tbody tr.dropup").removeClass("dropup");
// Adding dropup class to the current last row
lastRow.addClass("dropup");
});
});
This is awesome, simple and lightweight, it also adheres to the linked question. Thanks Dave!

Related

Simplifying a piece of code that switches classes

I have the following piece of code that is placed in a render function. The function runs few times per second.
if ($play.hasClass(playClass)){
$play.removeClass("playing paused").addClass(playClass);
}else{
$play.removeClass("playing paused").addClass(playClass);
}
I want to make sure the code only runs if the playClass is does not exist in the $play element. if it does. Removes all classes and add the current version of playClass.
This is somehow what toggleClass does, but the difference is, since my codes runs few times per second, the toggleclass will keep changing the class.
What I want to achieve is that if the value of playClass does not exist in $play, then swap it with the previous one and only do it when it is different. Do not check it every time.
The value of $play can be either playing or paused.
This code is doing the job correctly, I just want to find out if there is a more efficient and professional way to do it.
Thanks in advance.
You don't need any ' if ' because they do the same.
just:
$play.removeClass("playing paused").addClass(playClass);

Where each variable is equal to spans content add class

The Question and Codes
I am struggling with the below code:
$('.rdsubs-mysubscriptions table tbody tr td a').each(function() {
var subItem = $(this).html();
//console.log(subItem);
var subItemStripped = subItem.substring(12);
console.log(subItemStripped);
$('body').find('span:contains("subItemStripped")').addClass('HELLO');
}); // end of each function
When I check the console for subItemStripped then it shows this:
Framework
Content
Slideshow
Which means (in my head at least ;-)) that for each span that is inside the body it should find one of these subItemStripped and where it finds a match it should add the class hello but this is not happening.
Actually, nothing is happening.
When I change this line:
$('body').find('span:contains("subItemStripped")').addClass('HELLO');
to
$('body').find('span:contains("Framework")').addClass('HELLO');
It works nicely. So am I putting the variable subItemStripped wrongly in there or has it something to do with the .each() function.
I tried the below things to make it work
With the above code I tried a couple of variations before I came here:
$('body').find('span:contains(subItemStripped)').addClass('HELLO');
$('body').find("span:contains('subItemStripped')").addClass('HELLO');
I also tried it with completely different sets of code I gathered from other SO posts but none of those worked. Why I don't know.
$("span").filter(function() {
return $(this).text() === subItemStripped;
}).addClass("hello");
$("span").filter(function() {
return $(this).text() === subItemStripped;
}).css("font-size", "6px");
Why do I need this
I know I don't have to explain why I need this but it could be useful in coming up with other great ideas if the above is not feasible.
I have a webpage and on that page is a menu filled with products that a user can download if he/she has access.
Each menu item has a span with the title in it. Those titles are built up like: Framework Content Slideshow
On this same page is also a component that shows all the users subscriptions.
With the above code, I look to all the subscriptions of the user. Which returns
CompanyName Framework CompanyName Content CompanyName Slideshow
Then I Strip .substring(12) all the parts that I know are not present inside the menu. Which leaves me with Framework Content Slideshow
At this point, I know that some menu titles and the stripped item are the same and for every match, I want to add a class upon which I can then add some CSS or whatnot.
Hopefully, the question is clear and thanks to everyone in advance for helping me out.
#gaetanoM You are completely right. Right after I posted the question I came on this site:
jQuery contains() with a variable syntax
And found the answer which is the same as you are saying!
$('body').find("span:contains('" + subItemStripped + "')").addClass('HELLO');
Thanks so much!
#gaetanoM Can you make your comment in an answer? Then I can select it as the accepted answer. I am answering this question now just to make sure it has an answer. As people get punished for asking questions that don't get answers.

Create new DOM element if a specific height was reached with part of the old content from DOM element before

Update: 27th December 2016
I did change the heading, since every DOM element could be the target (it actually doesn't matter if it is a <p> element or not).
I've provided some more informations about what I'm using and what I'm trying to achieve. Maybe there are native electron ways to achieve this? Or libs which could help me too?
Product: I'm going to extract tgz files with XMLs in it. Those XMLs will be used to automatically fill tables in the finished product. After that the tables and paragraphs will be editable where users can add new rows to the tables and also add new paragraphs to the page.
Framework: I'm using electron to fire the whole thing up.
Backend: NodeJS 7.x.x to make use of ES6 features
Libraries: jQuery, Bootstrap, Angular, Materialize, lodash, async, moment
Please keep in mind that I already did achieve all of my product needs. My original question was and still is if there is a more performant way of doing this:
I have a html page which can have 'n' containers called pages. A page can hold multiple <p> elements. This <p> elements are set to contenteditable="true".
Now I'm trying to create a javascript function which is checking the single page height with something like this:
// Set max container height to 10cm.
let containerMaxHeight = 377.95276 // 1 cm = 37.795276px;
if(containerElement.clientHeight > containerMaxHeight){
/**
* do desired stuff.
*/
}
everything easy so far. The function is getting the innerHTML of the <p> element which is currently beeing edited and "break the site" into a new site if the page height is above the limit. I have thought out a recursion wich is removing words (most of the time 1-3) of the old <p> element and inserting them to a newly created page with a <p> element until the maximum height of the old page is set to its maximum value.
Here is an example of my recursion (simplified) which is removing words from the end of innerHTML like this:
let lastWordToBeRemoved = oldParagraphElement.split("\\s+").pop();
// append old value to new <p>
newParagraphElement.innerHTML += lastWordToBeRemoved;
// remove last Word from old <p>
oldParagraphElement.innerHTML.slice(0, -lastWordToBeRemoved.length);
/**
* Recheck height of old page container if it is above the
* maximum redo above code
*/
I've startet out with this example:
https://delight-im.github.io/HTML-Sheets-of-Paper/
as you can see the pages are getting bigger and bigger if you edit them. I've already prevented that with my JS function.
Now that you have an idea of what I'm doing: Is there a more performant and or elegant way of doing this? I'm highly interested to hear how you would solve this problem.
If there is anything still unclear let me know, I will update my answer.
Thank you in advance!
Regards,
Megajin
Instead of splitting words, I think you should insert another p element into the expected position instead. Then you can easily move the exceeding paragraph into the new page. For example
paragraphElement.innerHTML = paragraphElement.innerHTML.replace(lastWordToBeRemoved, '</p><p class="exceeding-paragraph">' + lastWordToBeRemoved);
newPage.insertBefore(oldPage.querySelector('.exceeding-paragraph'), newPage.firstElementChild);

Alternating row color based on previous row using jquery

I have a table of dynamically generated content (PHP from mysql). The first column is always a date. Some records share the same date.
My goal is to style all records with the same date with the same background color and for the date to only appear in the first event of that day.
I'm no javascript/jquery expert, but here is my first go. It is not yet fully functional.
Here are my two problems:
1: Cannot get the repeated dates to disappear (see note in code)
2: The whole method of adding classes according to the content of the cell above seems incredibly slow. Page loads are around 10-12 seconds with a table of about 100-150 rows. Is this the fastest method to achieve this?
$(document).ready(function(){
$("td.date").each(function(){
var cellAbove = $(this).parent().prev().children(".date").html();
if ($(this).html()!==cellAbove){$(this).parent().addClass("firstDate");}
if ($(this).html()==cellAbove){$(this).parent().addClass("multiDate");}
});
$("tr.firstDate").filter(":even").css("background-color","#FFFFFF");
$("tr.firstDate").filter(":odd").css("background-color","#F4F4F4");
$("tr.multiDate").each(function(){
$(this).children(".date").text(); //NOT FUNCTIONING
$(this).css("background-color",$(this).prev().css("background-color"));
});
});
<table>
<tr>
<td>DATE</td>
<td>EVENT</td>
</tr>
<tr>
<td class="date">January 5, 2013</td>
<td>Board Meeting</td>
</tr>
...
</table>
I think the fastest implementation would be to filter out the values and set your html classes server-side using PHP.
But I went ahead and wrote a JS version for you anyways (and for my morning problem-solving) =)
Your first function was at almost a 2n algorithm because you were running 2 different loops. My first suggestion is to do the work in the first loop. Also, every time you use a jQuery selector, you are also performing a loop. jQuery isn't instantaneous, and is essentially traversing all DOM elements (another loop!) to find your elements. I count 7 jQuery selectors in your code, and 2 "each" loops, for a total of 9 loops. You can save your jQuery objects if they will be reused, so you don't have to "re-loop" to acquire them. For example, in the future you can save your $("tr.firstDate") object in a variable since you use it twice. In my code, you can see that I save my $me variable for future use. If I wanted to make it even faster, I could save the $me.html() value as well. Using this approach for much larger applications, you would have to consider the trade-off of memory size vs. speed.
Also, I used the .html("") method to clear the contents of the cells you wanted empty.
Another suggestion is to use CSS to decide the color, rather than setting the color using jQuery. Add the class and then have your CSS do the work. You can see in my code that I only add the .alt class to the rows I want with the alternate color.
.alt td { background: #666; }
Also, don't rely on styling the tr background color. I don't think this is supported cross-browser. I would style the td instead. Also, in my jsFiddle I used th tags for your headers, for semantic purposes.
Here is a jsFiddle. The javascript is below:
$(document).ready(function(){
var parity = true;
var curDate = null;
$("td.date").each(function(){
var $me = $(this);
if(curDate == null || curDate != $me.html())
{
curDate = $me.html();
parity = !parity;
}
else
$me.html("");
if(parity)
$me.parent().addClass("alt");
});
});
Hope this helps!

Detect checkbox change in jstree

I am using the latest jstree commit from github with the checkbox plugin as a part of my form. I am using the tree with the "real_checkboxes" attribute.
Everything is fine except the checkbox plugin does not actually add any changed property attribute to the hidden field and nor does it seem to have a external function that will allow me to hook in to create custom functionality.
Is it possible for me to understand and listen for when a checkbox is either ticked or unticked?
Thanks,
UPDATE: after doing some experimenting I was able to over ride the default functionality of the check and uncheck methods using:
$.jstree._instance.prototype.check_node = function(node){ alert("here"); }
However it isn't very clean and it does override the whole method.
Is there:
a) a cleaner way to do it?
b) a way to just do a callback on the function rather than replacing the whole damn thing?
Thanks again,
#Noctyrn
Yes I did that originally but then I looked through the docs a lot more closely and found this:
$(".js_tree_'.$this->attribute.' div").bind("check_node.jstree", function(){});
But yes your function does the same :). But since mine is right to the jsTree docs Ima mark my answer as the right one. Also that function allows for different trees on the same page to have different binds so it is better overall :).
Thanks for the help :),
This is actually less clean but at least it gets the job done:
var check_node_func = $.jstree._instance.prototype.check_node;
$.jstree._instance.prototype.check_node = function(node) {
check_node_func.apply(this, arguments);
alert("here");
}

Categories