I want a checkbox on a web page. When I click it, it sends an ajax request to the server. When the server replies, I want the checkbox to change. I can fix everything except the fact that the checkbox immediately changes state when clicked.
Are you sure you really want this? An Ajax-Request can take its time. When the user gets no feedback, they may be inclined to click again and again, until something happens. When this deactivates the button (again after some time) the user gets even more puzzled.
Rather think about providing immediate feedback (e.g. check the box) and display an indicator next to it, that signals communication with the server (e.g. the famous spinning wheel). When the result is back, hide the indicator and deactivate the checkbox if needed. You may also want to inhibit posting the form during the ajax request.
You could probably do something like this: when the checkbox is clicked, set the checkbox to "disabled" (this greys out the checkbox and makes it uneditable), make your ajax call, and once you get the ajax return remove the "disabled" from the checkbox. Something like this (using jQuery, untested):
$('#mycheckbox').click( function() {
var checkbox = this;
$(checkbox).attr('disabled','1');
$.post( url, data, function() {
// if successful
$(checkbox).removeAttr('disabled');
}
}
Add to your onclick "return false;" and it should not change.
<input id="theChkbox" type="checkbox" onclick="this.checked=!this.checked;sendAjaxRequest(this);">
this.checked=!this.checked will reset the state of the checkbox to what it was before it was clicked. This should work in all browsers without the state flickering (too much).
sendAjaxRequest() will do your magic and when the request comes back set the appropriate checked state of the checkbox. Passing this to sendAjaxRequest() should give you a reference to the checkbox so you can adjust its state. Failing that, just use document.getElementById("theChkbox") to retrieve a reference to it to set its state.
You could start your onchange method with checkbox.checked=NOT checkbox.checked (you may have to modify this for your language of choice), you'll probably get a flicker but it should put it back quickly enough.
I think you should use other approach indeed. Maybe a button/image button because you want to fire some actions for a click to represent a specific command (desire) from the user. I will try to explain better: i think you have some info in the page and some gadgets where the user can click and do something (add an item to a cart) and i think it is more usable if the gadget has more visual appeal to the user than a checkbox (i.e. a "add it" for instance).
Hope this help.
Related
I was creating a Dropdown component for React. Inside the dropdown, I have a form of radio group buttons.
<DropdownButton />
<DropdownForm />
In the DropdownButton, I have an state to know if it is open or not. Depends on that, DropdownForm it's hidden or not (using display: none).
The use case is: User selects a radio button, click apply and something happen. However, if user selects some radio button, and mouse out the dropdown (without clicking the apply button), the one that is selected should be the one that I get from the store.
Something like:
render: function () {
...
if(store.getSomeParam() != this.state.someParam && !this.props.isOpen){
someParam = store.getSomeParam()
}
Then the radio buttons are like:
<input checked={someParam == "something"} ... />
It doesn't really work. It re-renders but it doesn't change the button that is checked. I also tried with refs:
this.refs.myInput.getDOMNode().checked = true
But still nothing. Is this a correct behaviour?
The only solution I found so far is not using a css hiding class (display: none). So what I do is that the DropdownButton renders the DropdownForm depending on if it's open or not (so if you close it, you are forcing DropdownForm to unmount). Then when opening again, it is taking the values from the store (getInitialState) and it shows the correct radio button selected. But, I am not sure if this is the best solution and if there is any drawback in unmounting the component instead of just css hiding it.
This probably has nothing to do with React at all.
Most browsers don't validate the value of the checked attribute, but merely if it is there or not: http://jsfiddle.net/7jzm7gvw/
Just set the checked attribute to either true or null:
<input checked={someParam == "something" ? true: null} ... />
TL;DR: You must use the componentDidMount lifecycle method, not render, to work with the rendered dom nodes directly.
I was struggling with this as well, and after doing some online research I figured I might as well look into it for myself. Here's what I came up with:
Use the componentDidMount lifecycle method and update whatever you need to in there. Here's a Pen I used to prototype this, and I think it looks okay: http://codepen.io/gholts/pen/GpWzdb
You could drop this in pretty easily to what your'e working on by just putting a componentDidMount method on your object and doing it there. I used document.getElementById but you could definitely use jQuery or whatever else you wanted in there, as once the component has mounted it's available to DOM selectors.
I'm using this now to update 20 radio button groups (so it has to check a prop for three different states and update accordingly) and it loads instantly.
Hope it helps! I used the ES6 class syntax in my Pen, you should check it out if you have some time to refactor :) It's fun.
EDIT: So I figured it out, I'm a dummy. You don't need to do the whole document.getElementById business that I was doing. Just use your this.refs.whichever.getDOMNode().checked = true and it'll work, so long as you do it in componentDidMount. It works there because there is an actual DOM element on the page at that point.
I have client sided code in the onClientLoad event of my form that governs field hiding. Problem is, it depends on values in the first tabPanel. If I switch to the second tabPanel, it stops working. I can no longer switch back to any other tabPanel.
How can I within the onClientLoad event using CSJS identify which panel I currently am on?
In a tab panel whenever you switch between tabs the fields are recalculated.
So, I would rather suggest you to put a visibility formula on field instead.
Make sure all tab panels have a nice id. Then in your script block you can add something like:
var t1 = dojo.byId("#{id:tab1}");
if (t1) { // do your stuff }
Does it work for you?
long-time lurker here asking my first public questions because I am truly stuck.
I'm working on a hosted shopping cart platform so I only have access to add code in certain designated divs. I have a javascript code that I'm calling externally (because inline is bad unless you have to, right?)
So my issue is, There is a <select> dropdown that I do NOT have direct access to change HTML and the silly shopping cart platform didn't give it an id, only the name attribute is set.
I need to clear the <div id="result_div"> when the <select name="ShippingSpeedChoice"> drop-down is clicked so I have:
$("[name=ShippingSpeedChoice]").change(function(e) {
$("#result_div").empty();
});
It fires once, but that's it. My question is, how do I make it fire EVERY TIME the <select name="ShippingSpeedChoice"> is clicked?
Here's all the relevant javascript (in case it's preventing #result_div from clearing somewhere):
$("[name=ShippingSpeedChoice]").change(function(e) {
$("#result_div").empty();
});
$("#btn_calc").click(function(e) { /// onclick on Calculate Delivery Date button
Thanks in advance, any help is appreciated!
If you want something to happen every time the element is clicked, use .click() rather than .change(). The latter only fires if they select a different value from the menu than it had before.
$("[name=ShippingSpeedChoice]").click(function(e) { $("#result_div").empty(); });
First of all, I'd probably try and setup the shopping cart select to have an id.
$("[name=ShippingSpeedChoice]").id = 'shopping_cart_select';
then try binding the "change" function to the element via it's id.
$('#shopping_cart_select').bind('change', function(){
//rest of code goes here
}
I still wasn't able to use the name attribute to call the function, so I found a way around it by using the id of the td the ShippingSpeedChoice dropdown was in:
$("#DisplayShippingSpeedChoicesTD").change(function(e) {
$("#result_div").empty();
And it fires every time now. Thank you so much for all your feedback & assistance - I still wish I could figure out how to use the name attribute rather than the id, but that will be a puzzle for another day!
I am trying to append new returned data to my select tag when user selects a drop down menu
obj.prototype.getText=function(){
codes....
call ajax....
ajax.callback=function(data){
$('#option').append(data);
}
}
$('#dropdown').on('change', function(){
obj.getText()
})
My problem is that I only want to append data when the user clicks the dropdown menu the first time.
my code will keep append more same data to my #option as long as user keeps clicking the drop down menu...
Are there anyways to fix this? Thanks a lot.
Use .one() instead of .on(). It unbinds itself once you trigger the event once:
$('#dropdown').one('change', obj.getText);
You could simply remove the on change event, so it's no longer triggered.
$('#dropdown').off('change');
I would also look into the notion of a "run once" command. This isn't really what I would recommend here, but going forward, it's a cool thing to know. underscore.js does it well
You need to turn off the handler.
something like this.
$('#dropdown').on('change', function(){
obj.getText()
$('#dropdown').off('change');
})
That is probably the best way , turn of event handler , or you could always store a bool value in a hidden field , like
<input type="hidden" id="hidAleadyAppended" />
and then set it to true after it is appended once.
This way if you ever need to know if it has been appended already in other code, that is a quick reliable way to check
I am using elSelect with mootools to change the look and fell of a select box. My problem is how can i call an ajax function when select box value changes?
<script type="text/javascript">
window.addEvent('domready', function() {
var mySelect = new elSelect( {container : 'someId'} );
});
</script>
Thanks in advance
Since elSelect changes the HTML structure to replace the dropdown, you can't use the change event set on the original dropdown. The documentation doesn't show any way to bind events to the replaced dropdown.
I'm not at all familiar with the way mootools works, but I notice in the source of the plugin that it has several event handlers defined, among which is onOptionClick. This gets triggered every time the user clicks an option in the dropdown. You can piggyback on top of it - change the code in that function to also trigger your ajax request.
Another option would be analyse the HTML structure of the injected elements - you can start from the id you give the constructor and look for .option elements inside it. You can them poll them for changes at fixed intervals (using setInterval) and send ajax requests when you see the value has changed. Or you can add click handlers to each option and take it from there.