Set time out event on a m() generated element - javascript

I have a m("p.help") element which is removed with a click event.
I also want the element to be removed automatically after a few seconds if not clicked. I need to set a time out on it. Setting time out does not work.
function help() {
var text = `This is a service template. Use Service section to set the schedule`;
var node = m("p.help", {
onclick() {
this.parentNode.removeChild(this);
},
}, text);
setTimeout(() => {
if (node.parentNode) {
node.parentNode.removeChild(node);
console.log("removed");
m.redraw();
}
}, 5000);
return node;
}
The click event works fine but the time out does not work. It is not even triggered judging by the console.log()
What am I doing wrong?
EDIT
Thanks ciscoheat for the tip.
I had to put the timer in the controller for this to work.
So this one works fine:
function controller(init) {
this.display = {
help: true
};
setTimeout(() => {
this.display.help = false;
m.redraw();
}, 5000);
}
function view(vm) {
return m(".container", [
(() => {
var text = "Some text";
if (vm.display.help) {
return m("p.memo", {
onclick() {
this.parentNode.removeChild(this);
}
}, text);
}
})(),
]);
}

To use Mithril correctly, you should avoid DOM manipulation, leaving that to Mithril's fast diff algorithm.
Use a state variable instead, related to displaying the help paragraph that will be changed automatically after 5 seconds.
Here's a jsbin showing what I mean: http://jsbin.com/kixece/edit?html,js,output

Related

jQuery to Javascript adding required attribute

So I have the following jQuery code that I've built out that checks whether a on change event has been triggered on #rtk5 and then either removes or adds the 'required' attribute.
Works perfectly in jQuery:
// Make checkbox textboxes not required unless checked
$(document).ready(function() {
$('#rtk5').change(function() {
if ($('.rtk5ReqField').attr('required')) {
$('.rtk5ReqField').removeAttr('required');
}
else {
$('.rtk5ReqField').attr('required','required');
}
});
});
I would like to convert it to JavaScript with a function call, but I can't seem to figure out how to properly do it.
Error:
TypeError: rtk5req.getAttribute is not a function
Here is my attempt:
var rtk5req = document.getElementsByClassName('rtk5ReqField');
function rtk5Required() {
rtk5req.addEventListener('change', (e) => {
if (rtk5req.getAttribute('required')) {
rtk5req.removeAttribute('required');
} else {
rtk5req.getAttribute('required', 'required');
}
});
}
rtk5req.addEventListener('change', rtk5Required());
document.addEventListener('DOMContentLoaded', rtk5Required);
rtk5Required();
Updated code: Removed the repetitive change call
var rtk5req = document.getElementsByClassName('rtk5ReqField');
function rtk5Required() {
if (rtk5req.getAttribute('required')) {
rtk5req.removeAttribute('required');
} else {
rtk5req.getAttribute('required', 'required');
}
}
rtk5req.addEventListener('change', rtk5Required());
document.addEventListener('DOMContentLoaded', rtk5Required);
rtk5Required();
Updated code #2:
Thanks all for all the hard work, there's one small issue that I'm still experiencing and had to make some tweaking - When I uncheck the checkbox, it doesn't remove the required tag placed on rtk5Declaration from which it did in the jQuery.
var rtk5_selection = document.getElementById('rtk5');
document.addEventListener('DOMContentLoaded', () => {
rtk5_selection.addEventListener('change', () => {
if (rtk5_selection.getAttribute('required')) {
document.getElementById('rtk5Declaration').removeAttribute('required');
} else {
document.getElementById('rtk5Declaration').setAttribute('required', 'required');
}
});
});
Thanks so much all!
Since you only have one element you should be using its ID instead of its class, and avoiding the complication caused by document.getElementsByClassName returning a pseudo-array of elements instead of a single element.
NB: use setAttribute to change an attribute's value, or better yet (as shown in the code below) use the direct boolean property that mirrors the element's attribute.
document.addEventListener('DOMContentLoaded', () => {
const rtk_sel = document.getElementById('rtk5');
const rtk_dec = document.getElementById('rtk5Declaration');
rtk_sel.addEventListener('change', () => {
rtk_dec.required = !rtk_sel.checked;
});
});
Thanks all for the contribution, below is the working version which I have tweaked:
var rtk5_selection = document.getElementById('rtk5');
var rtk5declaration = document.getElementById('rtk5Declaration');
function rtd3Declaration() {
if (!rtk5_selection.checked) {
rtd3declaration.removeAttribute('required');
} else {
rtd3declaration.setAttribute('required', 'required');
}
}
rtk5_selection.addEventListener('change', rtd3Declaration);
document.addEventListener('DOMContentLoaded', rtd3Declaration);
rtd3Declaration();

Vuejs - On input, run a function (but with a delay)

I have an input field, and v-on:input it runs a method called activate that looks like this:
export default: {
data() {
return {
isHidden: true
}
},
methods: {
activate() {
this.isHidden = false;
}
}
}
isHidden turns on/off some icon (it doesn't really matter what this data property is; I'm just using it for example purposes).
So currently, when a user does an input it immediately turns on the activate function. Is there a way to, perhaps, put it on a delay via setTimeout? I've tried doing the following but it doesn't work:
methods: {
setTimeout(function() {
activate() {
this.isHidden = false;
}
}, 500)
}
Try this:
methods: {
activate() {
setTimeout(() => this.isHidden = false, 500);
}
}
Or without arrow function:
methods: {
activate() {
var that = this;
setTimeout(function() { that.isHidden = false; }, 500);
}
}
First, set a var in your data:
data() {
return {
typing: Date.now()
}
}
then in your methods, create a function that will fire on keyup:
pendingSave(val){
let saving = setTimeout(() => {
this.saveItem(val) // method to call when user is done typing
},1203)
if(val){
saving
if(Date.now() - this.typing < 1200) clearTimeout(saving)
this.typing = Date.now();
}
}
In your HTML, you would have something like this:
<input v-model="title" v-on:keyup="pendingSave(title)" type="text" placeholder="Title" />
What happens is that when the user clicks inside the input, and types a character, it will call 'pendingSave()'. This will get the function ready to call via setTimeout() in 1203ms. If the user types another character, and the time is 'less' than 1200ms, it will cancel setTimeout()... otherwise it will fire the function saveItem() as intended.

How to stop calling a delayed function if some other event happens in that period?

After a certain event happens, I have this function (rightMenu) that triggers with 1.5s delay. However, my challenge is to figure out how to check if the leftMenu is called during this period then stop the setTimeout function to call the rightMenu.
var leftMenu = function() {
// some code here
}
var rightMenu = function() {
// some code here
}
$('#leftMenu').on('click', function() {
leftMenu();
})
$('#rightMenu').on('click', function() {
rightMenu();
})
if (...) {
leftMenu();
} else {
setTimeout(function() {
rightMenu();
}, 1500);
}
I'm not 100% sure if this is what you're asking, but you can clear intervals. For example:
function asyncFun() {
// some code
}
setTimeout(asyncFun, 5000); // this will run after 5 seconds
var asyncHandle = setTimeout(asyncFun, 10000);
clearTimeout(asyncHandle); // this cancels the function call
I feel like this is what you're asking...
If not, the other interpretation that I have is you want to temporarily remove the event handler from the #leftmenu and #rightmenu when you're in the other menu. To do this, you can clear event handlers in jQuery with $("#rightmenu").off("click"). This function is basically the opposite of .on. See here. Good luck!
Yet another possible fix to your code:
/*
initialize your variable here. Technically doesn't change anything
because of hoisting, but I'm guessing based on your question you
haven't learned that yet.
*/
var callingRight;
var leftMenu = function() {
// some code here
}
var rightMenu = function() {
// some code here
}
$('#leftMenu').on('click', function() {
clearTimeout(callingRight); // clear the timeout on your global variable here.
leftMenu();
})
$('#rightMenu').on('click', function() {
rightMenu();
})
if (...) {
leftMenu();
} else {
callingRight = setTimeout(function() { // assign this setTimeout to your global variable
rightMenu();
}, 1500);
}

How to prevent browser.driver.sleep

I have the below spec which is working fine, but I want to prevent using browser.sleep():
it('should go to the item details page', function () {
browser.get(testOptions.baseUrl+testOptions.cpdmPath+testOptions.itemDetailsForAttachment);
browser.getCurrentUrl().then(function() {
//browser.driver.sleep('4000');
console.log('inside then 4');
browser.driver.sleep('4000');
element(by.css('.md-header-items-container')).isDisplayed().then(function (isVisible) {
if (isVisible) {
// element is visible
browser.driver.sleep('4000');
element.all(by.repeater('(key, value) in tabList')).count().then(function (numberOfTabs) {
//console.log(numberOfTabs);
});
element.all(by.repeater('(key, value) in tabList')).get(4).click().then(function () {
browser.driver.sleep('4000');
element(by.css('.hidden-attachment-info-bar')).isDisplayed().then(function (isVisible) {
expect(isVisible).to.equal(true);
})
});
} else {
// element is not visible
console.log('is invisible');
}
});
})
});
A common alternative to using sleep() with hardcoded time intervals is to use wait() and explicitly wait for a specific condition to be met. For example, wait for element to be visible:
var EC = protractor.ExpectedConditions;
var elm = element(by.css('.md-header-items-container'));
browser.wait(EC.visibilityOf(elm), 4000);
Finally, I got it working as below:
it('should go to the attachments page and pass waiting time for element', function() {
browser.get(testOptions.baseUrl+testOptions.cpdmPath+testOptions.itemDetailsForAttachment);
browser.wait(function() {
return browser.driver.isElementPresent(cpdmAttachTabPage.notificationBar);
}, 90000);
browser.driver.isElementPresent(cpdmAttachTabPage.notificationBar).then(function(isVisible) {
console.log(isVisible);
expect(isVisible).to.equal(true);
})
})

Wait until div is not visible to process next line

I need to write some code which is supposed to wait until a predefined div is no longer visible in order to process the next line. I plan on using jQuery( ":visible" ) for this, and was thinking I could have some type of while loop. Does anyone have a good suggestion on how to accomplish this task?
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if ($(".mstrWaitBox").attr("visibility")!== 'undefined') || $(".mstrWaitBox").attr("visibility") !== false) {
alert('inside else');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
$( document ).ready(function() {
$(".scroller-right" ).mouseup(function( event ) {
alert('right');
pollVisibility();
});
});
function pollVisibility() {
if (!$(".mstrWaitBox").is(":visible")) {
alert('inside if');
microstrategy.getViewerBone().commands.exec('refresh');
} else {
setTimeout(pollVisibility, 100);
}
}
div when not visible:
<div class=​"mstrWaitBox" id=​"divWaitBox" scriptclass=​"mstrDialogImpl" dg=​"1" ty=​"edt">​
</div>​
div when visible:
<div class=​"mstrWaitBox" id=​"divWaitBox" scriptclass=​"mstrDialogImpl" dg=​"1" ty=​"edt" visibility="visible">​
</div>​
You can use the setTimeout function to poll the display status of the div. This implementation checks to see if the div is invisible every 1/2 second, once the div is no longer visible, execute some code. In my example we show another div, but you could easily call a function or do whatever.
http://jsfiddle.net/vHmq6/1/
Script
$(function() {
setTimeout(function() {
$("#hideThis").hide();
}, 3000);
pollVisibility();
function pollVisibility() {
if (!$("#hideThis").is(":visible")) {
// call a function here, or do whatever now that the div is not visible
$("#thenShowThis").show();
} else {
setTimeout(pollVisibility, 500);
}
}
}
Html
<div id='hideThis' style="display:block">
The other thing happens when this is no longer visible in about 3s</div>
<div id='thenShowThis' style="display:none">Hi There</div>
If your code is running in a modern browser you could always use the MutationObserver object and fallback on polling with setInterval or setTimeout when it's not supported.
There seems to be a polyfill as well, however I have never tried it and it's the first time I have a look at the project.
FIDDLE
var div = document.getElementById('test'),
divDisplay = div.style.display,
observer = new MutationObserver(function () {
var currentDisplay = div.style.display;
if (divDisplay !== currentDisplay) {
console.log('new display is ' + (divDisplay = currentDisplay));
}
});
//observe changes
observer.observe(div, { attributes: true });
div.style.display = 'none';
setTimeout(function () {
div.style.display = 'block';
}, 500);
However an even better alternative in my opinion would be to add an interceptor to third-party function that's hiding the div, if possible.
E.g
var hideImportantElement = function () {
//hide logic
};
//intercept
hideImportantElement = (function (fn) {
return function () {
fn.apply(this, arguments);
console.log('element was hidden');
};
})(hideImportantElement);
I used this approach to wait for an element to disappear so I can execute the other functions after that.
Let's say doTheRestOfTheStuff(parameters) function should only be called after the element with ID the_Element_ID disappears, we can use,
var existCondition = setInterval(function() {
if ($('#the_Element_ID').length <= 0) {
console.log("Exists!");
clearInterval(existCondition);
doTheRestOfTheStuff(parameters);
}
}, 100); // check every 100ms

Categories

Resources