How can I make my jquery if/then statement update live? - javascript

I am trying to write a simple conditional that says if div1 is displayed, then change div2's display to none. However, I want this to be updated live. So anytime div1 display is 'grid', div2 disappears from sight.
<script>
if($('.div1').css("display") == "grid") {
$('div2').css({"display":"none"});
}
</script>
What am I doing wrong here?

A block of javascript code will not just magically run whenever convenient for you, unless you make it so that it is run in such a way. What you have written will just run once, and move on. Javascript will not by itself will look for when things change.
You need to track the change and run your code after that change. If you are writing the javascript for a site, you probably know when these changes occur, so you can execute your code block when they do occur. For example if div1 changes to grid when user clicks a button, then you can bind your function to its click event so handle the situation.
A more advanced method would be to watch for changes on DOM and run a function when they occur. You can do this with MutationObservers. You can do precisely what you want, if div changes to grid, run myFunction() for example.
Another method would be to have a function run on intervals but this is an obsolete technique which is prone to errors and crashes and is by no means recommended to be used in javascript.

The $.watch plugin can do this:
$('.div1').watch('display', function() {
var display = ($(this).css('display') === 'grid' ? 'none' : 'block');
$('.div2').css('display', display);
});
Unlike the setInterval method, here's what the library does (from the github page):
This plugin lets you listen for when a CSS property, or properties, changes on element. It utilizes Mutation Observers to mimic the DOMAttrModified (Mutation Events API) and propertychange (Internet Explorer) events.
Be aware that your original code uses $('div2') instead of $('.div2') and will only match elements that look like this: <div2>foo</div2>. I've changed it to a class in my example.

Related

Wrote alternative to jQuery Accordion, it spazzed. Why?

I wrote an alternative to the jQuery Accordion, as that didn't offer multiple open section support (any idea why they opted to not include support for that? What's the history there?). I did some research on StackOverflow, as well on Google to see what other options others came up. I needed something that could be used on the fly on multiple elements.
After seeing several solutions and experimenting with them, in the end, I wrote my own version (based on Kevin's solution from http://forum.jquery.com/topic/accordion-multiple-sections-open-at-once , but heavily modified).
jsFiddle can be found here: http://jsfiddle.net/3jacu/1/
Inline Code:
$(document).ready(function(){
$.fn.togglepanels = function(){
return this.each(function(){
h4handler = $(this).find("h4");
$(h4handler).prepend('<div class="accordionarrow">▼</div>');
$(h4handler).click(function() {
$(h4handler).toggle(
function() {
barclicked = $(this);
$(barclicked).find(".accordionarrow").html('►');
$(barclicked).next().slideUp('slow');
window.console && console.log('Closed.');
return false;
},
function() {
barclicked = $(this);
$(barclicked).find(".accordionarrow").html('▼');
$(barclicked).next().slideDown('slow');
window.console && console.log('Open.');
return false;
}
);
});
});
};
$("#grouplist").togglepanels(); }
Oddly, the accordion arrow at the right side stopped working once I pasted it in jsFiddle, while it works in my local copy.
In any case, the issue is that toggling isn't working as expected, and when it does, it fires duplicate toggle events which result in it closing, opening, then ultimately closing the section and it won't open from that point on (it toggles open then closes back). That's assuming it works! At first, it won't work as it doesn't respond. I think there's a logic error somewhere I'm missing.
From what I wrote/see in the code, it searches the given handle for the corresponding tag (in this case, h4), pops the handle into a variable. It then adds the arrow to the h4 tag while applying the accordionarrow class (which floats it to the right). It then adds a click event to it, which will toggle (using jQuery's toggle function) between two functions when h4 is clicked.
I suspect the problem here is that I may be mistakenly assuming jQuery's toggle function will work fine for toggling between two functions, that I'll have to implement my own toggle code. Correct me if I'm wrong though!
I'm trying to write the code so it'll be as efficient as possible, so feedback on that also would be appreciated.
Thanks in advance for your time, assistance, and consideration!
You have the toggle binding (which is deprecated by the way) inside of the click binding, so a new event handler is getting attached every time you click the header.
As a random aside you should also fire events within the plugin (where you have the console lines would make sense) so that external code can react to state changes.
I believe your issue is the $(h4handler).click(function() { you have wrapped around the toggle listener. Essentially what this was doing was making so every click of the tab was adding the toggle listener, which was then also firing an event. Removing the click listener will have the behaviour you expect.
You forgot to paste the trailing characters ); to close the function call to jQuery function ready. Fixed: http://jsfiddle.net/LeZuse/3jacu/2/
UPDATE: I've just realised I did not really answer your question.
You are duplicating the .toggle functionality with binding another .click handler.
The doc about .toggle says:
Description: Bind two or more handlers to the matched elements, to be executed on alternate clicks.
Which means the click event is already built in.
NOTE: You should use local variables instead of global, so your plugin won't pollute the window object. Use the var keyword for this:
var h4handler = $(this).find("h4");

Sharing an event across two scripts or using change is visibility state as an event trigger

OK I am lost here. I have read numerous postings here and else where on the topic of how to check for the state of a given element in particular whether it is visible or hidden and make the change of state trigger an event. But I cannot make any of the suggested solutions work.
Firstly, as every one seems to leap on this point first, the need to do this has arisen as I have one jQuery script which deals with displaying an svg icon in a clickable state. And another which already has functions to perform relevant actions when the form is made visible by clicking the icon and obviously I want to reuse these.
What I have tried:
Initially I tried have both the scripts acting on a single click event (this remains the ideal solution)....
Script 1:
$(".booked").on("click", function() {
$("#cancellation_Form_Wrapper").css("visibility","visible");
}).svg({loadURL: '../_public/_icons/booked.svg'});
Script 2:
$(".booked").on("click", function() {
// do stuff
});
This did not work so I tried to research sharing an event across two scripts but couldn't make any head way on this subject so I tried triggering another event for the second script to pick up....
Script 1:
$(".booked").on("click", function() {
$("#cancellation_Form_Wrapper").css("visibility","visible");
$("#cancellation_Form_Wrapper").trigger("change");
}).svg({loadURL: '../_public/_icons/booked.svg'});
Script 2
$("#cancellation_Form_Wrapper").on("change", function(event){
// do stuff
});
This did not work again I am unclear why this didn't have the desired effect.
Then I tried is(:visible) ....
Script 1
$(".booked").on("click", function() {
$("#cancellation_Form_Wrapper").css("visibility","visible");
}).svg({loadURL: '../_public/_icons/booked.svg'});
Script 2
$("#cancellation_Form_Wrapper").is(":visible", function(){
// do stuff
});
So I am a bit lost. The ideal would be to return to the first notion. I do not understand why the click event on the svg cannot be handled by both scripts. I assume that this has something to do with event handlers but I am not sure how I could modify the script so they both picked up the same event.
Failing that I could use the fact the visibility state changes to trigger the action.
Any guidance welcomed.
Edit Ok I have just resolved the issue with script 2 picking up the triggered event from script 1. Sad to say this was a basic error on my part ... the form was preventing the display of the alert. However I still cannot get the is(:visible) to work.
Your syntax may be off:
$("#cancellation_Form_Wrapper").is(":visible", function(){
// do stuff
});
should be:
if($("#cancellation_Form_Wrapper").is(":visible")){
// do stuff
});
EDIT: If you want something to happen after a div is made visible, you may want to use the show() callback rather than toggling visibility:
$('#cancellation_Form_Wrapper').show(timeInMilliseconds, function(){
// do something
});
However, this needs to take place in the same function, which I don't think improves your position.
The problem is probably that your second on() script is firing at the same time as your first, meaning the wrapper is not yet visible. You could try wrapping the second on() in a short timeout:
$(".booked").on("click", function() {
setTimeout(function(){
if($("#cancellation_Form_Wrapper").is(":visible")){
// do stuff
});
}, 100);
});
That should introduce enough of a delay to make sure the wrapper has been shown before trying to execute the second statement.

JQuery if statement for .is(':visible') not working

I have a div that when the page is loaded is set to display:none;. I can open it up using this simple code:
$(".field-group-format-toggler").click(function()
{
$(".field-group-format-wrapper").css({'display':'block'});
});
Once it's opened, I'd like the user to be able to close it so I tried using the .is(':visible') function and then wrapping my original code in an if statment but this time using display:none;
if($('.field-group-format-wrapper').is(':visible')){
$(".field-group-format-toggler").click(function()
{
$(".field-group-format-wrapper").css({'display':'none'});
});
}
This does not seem to work though and I am not getting any syntax errors that I know of.
I also tried this:
if ($('.field-group-format-wrapper').is(':visible'))
$(".field-group-format-toggler").click(function () {
$(".field-group-format-wrapper").css({'display':'none'});
});
... but that did not work either.
You can just use the toggle function:
$(".field-group-format-toggler").click(function()
{
$(".field-group-format-wrapper").toggle();
});
This will show the '.field-group-format-wrapper' elements if they are currently hidden and hide them if they're currently visible.
FYI the reason your code snippet in your question wasn't working is because you're only checking the visibility of the elements on dom ready, rather than on each click - so the event handler to show the elements will never be attached.
I guess your function is only being called on page load at which time all divs are hidden.
Why not check the visibility in the click event handler?
$('.field-group-format-toggler').click(function(){
var $wrapper = $('.field-group-format-wrapper'); //Maybe $(this).parent()?
if($wrapper.is(':visible'))
$wrapper.hide();
else
$wrapper.show();
As already mentioned, you can use the toggle function to achieve what you want.
To add a bit of extra information, when attaching events like you're doing, you're actually using a subscription model.
Registering an event puts it in a queue of events subscribed to that handler. In this case, when you add the second event to change the CSS, you're adding an event, not overwriting the first one.
Whilst thing isn't actually causing your problem, it's worth being aware of.

Should changes to the value of a SELECT control made in code trigger the onChange Event?

I'm using the following code to watch for changes to a given SELECT element.
someSelectElement.change(function () { alert('change made'); });
And it works peachy when I change the value the selected item through the UI.
However, It doesn't seem to trigger the event if the value is changed via a script. For example, the following code executed in the debugging console changes the selected item, but does NOT fire the event.
$('#someSelectElement').val('NewValue')
I know it seems unusual to need to detect changes made to the control by the other code, and if it was my code I'd just manually trigger the event and call it a day. The trouble is, I am writing a jQuery plug-in that needs to do something when the value of a watched control changes whether it be through user intervention or some client-side script that the user of my plug-in is running.
I'm assuming the behavior of not triggering events in this situation is by design. If not, please speak up and let me know what I'm doing wrong. If so, is there a workaround where I can watch for changes made to the value of a SELECT element regardless of whether they were user or code initiated?
Code-driven changes to element values don't trigger native events. You can always trigger them yourself, of course, via the jQuery ".trigger()" method.
The Mozilla browsers have long had a "watch" feature, but that's not supported by other platforms.
Okay - so I might have a better solution to this than the interval timer solution.
Also note that this is a MUCH larger hack and the following is simply proof of concept and by no means is production-ready:
$(document).ready(function(){
function change(){
$('#test option[value=3]').attr('selected', 'selected');
}
// run it before changing it
alert('first go');
change();
var tmp = String(change).replace(/function change\(\){/, '');
tmp = tmp.replace('}', '');
tmp += 'alert(\'it changed\');';
change = function() { eval(tmp); };
// try it again - should get the second alert this time
alert('second go (post mod)');
change();
});
See the sample here.
Essentially, what I'm doing is:
Convert the function to a string
Replace the bounding function constructs
Add whatever functionality I want to inject
Reassign the modified function to the original function
Seems to work, but might not in the real world :)

Checking to see if a DOM element has focus

I've got a lightbox textbox that is displayed using an AJAX call from an ASP.NET UpdatePanel. When the lightbox is displayed, I use the focus() method of a textbox that is in the lightbox to bring focus to the textbox right away.
When in Firefox, the text box gains focus with no problem. In IE, the text box does not gain focus unless I use
setTimeout(function(){txtBx.focus()}, 500);
to make the focus method fire slightly later, after the DOM element has been loaded I'm assuming.
The problem is, immediately above that line, I'm already checking to see if the element is null/undefined, so the object already should exist if it hits that line, it just won't allow itself to gain focus right away for some reason.
Obviously setting a timer to "fix" this problem isn't the best or most elegant way to solve this. I'd like to be able to do something like the following:
var txtBx = document.getElementById('txtBx');
if (txtPassword != null) {
txtPassword.focus();
while (txtPassword.focus === false) {
txtPassword.focus();
}
}
Is there any way to tell that a text box has focus so I could do something like above?
Or am I looking at this the wrong way?
Edit
To clarify, I'm not calling the code on page load. The script is at the top of the page, however it is inside of a function that is called when ASP.NET's Asynchronous postback is complete, not when the page loads.
Because this is displayed after an Ajax update, the DOM should already be loaded, so I'm assuming that jQuery's $(document).ready() event won't be helpful here.
Try putting the javascript that sets focus at the end of the page instead of the beginning or having it fire after the page loaded event. That will help ensure that the DOM is completely loaded before setting focus.
I've used FastInit for this. JQuery $(document).ready() would also work.
You can try this:
Use the endRequest event of the PageRequestManager. That event fires once an Ajax update has finished.
Focus the textbox in the event handler
Here is some sample code:
<script type="text/javascript">
function onRequestEnd()
{
var txtBx = $get('txtBx');
txtBx.focus();
}
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onRequestEnd);
</script>
To focus the textbox initially you can use the pageLoad function (shortcut to the load event of the Application client-side object):
<script type="text/javascript">
function pageLoad()
{
var txtBx = $get('txtBx');
txtBx.focus();
}
</script>
you could try something like this [IE Specific]. (untested)
theAjaxCreatedElement.onreadystatechange = function() {
if ( this.readyState != "complete" )
return;
this.focus();
};
Another way might be to change the background color of the element with onfocus, then retrieve it with js check if it is what it should be, if not: refocus the element.
It seems that IE does not update the DOM until after the script has finished running. Thus, a loop testing for focus will not allow the DOM to update. Using setTimeout is probably the only working solution.
Your example with .focus() is a well known example, see e.g. this answer.
Have you tried adding the autofocus="autofocus" attribute to the textbox element you are calling via Ajax?
Normally, when I need certain additional JavaScript functionality to run on dynamic content, I'll simply add that JavaScript to the content being called as well.
That JavaScript will also execute after it's added to the DOM. I don't see a point in writing JavaScript to your parent file and then "listening" for changes to the DOM. Like you mentioned, setTimeout() is more of a hack than anything else for something like this :)
There are several things in IE, that does the trick:
If focusing element has different z-index - you can quickly set z-index to that of currently focused element (possibly setting hidden attribute), set focus, and then set it back to original z-index.
Try to blur() currently focused element.
If element is 'shimmed' - focus the 'shim' element.

Categories

Resources