select2 AJAX control disturbs tab ordering - asp.net

I am using select2 on dropdownlist of asp.net. The code is as follows:
<script type="text/javascript" src="js/select2.min.js"></script>
<link type="text/css" rel="Stylesheet" href="css/select2.css" />
var v = /* get the select control */
v.select2();
The problem is, once select2() function is called, tab ordering stops working. Therefore, when on the dropdownlist tab key is pressed, focus do not move to the control having next highest tabindex but move seemingly randomly to some other control.
Commenting the line where the function is called solve this problem but I need the filtering. I have tried some of the other techniques of filtering discussed here but they are too complicated. Select2 is very simple and useful because all you have to do is include the JS and CSS files and call the function.
How can I solve this ordering problem? Alternatively, is there another filtering option as easy to use as select2 that would help me?

After a few hours of struggle, I have solved the problem. It turns out that the select2 AJAX control do destroy the tab order if the tab is pressed as soon as it gets focus, that is, when nothing is typed in it. It does not, however, destroy tab ordering if some text is typed.
The internal structure of select2's auto-generated HTML is like following:
<div class="select2-container">
<a class="select2-choice">
<span</span>
<abbr class="select2-search-choice-close" />
<div> <b></b> </div>
</a>
<div class="select2-drop select2-offscreen">
<div class="select2-search">
<input class="select2-input select2-focused" tabIndex=<somevalue> />
</div>
<ul class="select2-results></ul>
</div>
</div>
If some text is typed in the HTML select control, then tab ordering is working correctly, if no text is typed then tab order is destroyed. I have used document.activeElement in firebug to find focused control in both cases. In case of no text the anchor element has focus, and in case of text typed the HTML input element has focus.
As shown above, while select2.js correctly set tabIndex property of HTML input element, it does not of the anchor element.
Solution
Just add the following line at the position specified further below in select2.js:
this.container.find("a.select2-choice").attr("tabIndex", this.opts.element.attr("tabIndex"));
Add the line after:
this.opts.element.data("select2", this).hide().after(this.container);
this.container.data("select2", this);
this.dropdown = this.container.find(".select2-drop");
this.dropdown.css(evaluate(opts.dropdownCss));
this.dropdown.addClass(evaluate(opts.dropdownCssClass));
this.dropdown.data("select2", this);
this.results = results = this.container.find(resultsSelector);
this.search = search = this.container.find("input.select2-input");
and before:
search.attr("tabIndex", this.opts.element.attr("tabIndex"));
this.resultsPage = 0;
this.context = null;
// initialize the container
this.initContainer();
this.initContainerWidth();
installFilteredMouseMove(this.results);
this.dropdown.delegate(resultsSelector, "mousemove-filtered", this.bind(this.highlightUnderEvent));
installDebouncedScroll(80, this.results);
this.dropdown.delegate(resultsSelector, "scroll-debounced", this.bind(this.loadMoreIfNeeded));
So it becomes:
this.results = results = this.container.find(resultsSelector);
this.search = search = this.container.find("input.select2-input");
this.container.find("a.select2-choice").attr("tabIndex", this.opts.element.attr("tabIndex")); /* atif */
search.attr("tabIndex", this.opts.element.attr("tabIndex"));
this.resultsPage = 0;
this.context = null;
Make this change in select2.js. Obviously, you need to use the full js version, not the min version.
All you have to do is add one line, stated above. This would become line no#504 in VS2008 if done correctly.

Related

How to Attach Events to Table Checkboxes in Material Design Lite

When you create a MDL table, one of the options is to apply the class 'mdl-data-table--selectable'. When MDL renders the table an extra column is inserted to the left of your specified columns which contains checkboxes which allow you to select specific rows for actions. For my application, I need to be able to process some JavaScript when a person checks or unchecks a box. So far I have been unable to do this.
The problem is that you don't directly specify the checkbox controls, they are inserted when MDL upgrades the entire table. With other MDL components, for instance a button, I can put an onclick event on the button itself as I'm specifying it with an HTML button tag.
Attempts to put the onclick on the various container objects and spans created to render the checkboxes has been unsuccessful. The events I attach don't seem to fire. The closest I've come is attaching events to the TR and then iterating through the checkboxes to assess their state.
Here's the markup generated by MDL for a single checkbox cell:
<td>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect mdl-data-table__select mdl-js-ripple-effect--ignore-events is-upgraded" data-upgraded=",MaterialCheckbox">
<input type="checkbox" class="mdl-checkbox__input">
<span class="mdl-checkbox__focus-helper"></span>
<span class="mdl-checkbox__box-outline">
<span class="mdl-checkbox__tick-outline"></span>
</span>
<span class="mdl-checkbox__ripple-container mdl-js-ripple-effect mdl-ripple--center">
<span class="mdl-ripple"></span>
</span>
</label>
</td>
None of this markup was specified by me, thus I can't simply add an onclick attribute to a tag.
If there an event chain I can hook into? I want to do it the way the coders intended.
It's not the nicest piece of code, but then again, MDL is not the nicest library out there. Actually, it's pretty ugly.
That aside, about my code now: the code will bind on a click event on document root that originated from an element with class mdl-checkbox.
The first problem: the event triggers twice. For that I used a piece of code from Underscore.js / David Walsh that will debounce the function call on click (if the function executes more than once in a 250ms interval, it will only be called once).
The second problem: the click events happens before the MDL updates the is-checked class of the select box, but we can asume the click changed the state of the checkbox since last time, so negating the hasClass on click is a pretty safe bet in determining the checked state in most cases.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
$(document).on("click", ".mdl-checkbox", debounce(function (e) {
var isChecked = !$(this).hasClass("is-checked");
console.log(isChecked);
}, 250, true));
Hope it helps ;)
We currently don't have a way directly to figure this out. We are looking into adding events with V1.1 which can be subscribed to at Issue 1210. Remember, just subscribe to the issue using the button on the right hand column. We don't need a bunch of +1's and other unproductive comments flying around.
One way to hack it is to bind an event to the table itself listening to any "change" events. Then you can go up the chain from the event's target to get the table row and then grab the data you need from there.
You could delegate the change event from the containing form.
For example
var form = document.querySelector('form');
form.addEventListener('change', function(e) {
if (!e.target.tagName === 'input' ||
e.target.getAttribute('type') !== 'checkbox') {
return;
}
console.log("checked?" + e.target.checked);
});

dart MouseEvent toElement null

in my program I generate buttons inside an HTML table each with the same onClick.listen listener defined.
In the listener, MouseEvent event.toElement is null.
The table is pre-created in HTML, but the table rows, row cells and buttons in the cells are all generated in dart.
How come event.toElement can be null?
If I try a clean sample app (new web application in dart editor) and create a button, add that to a div, then event.toElement is not null.
So I have a general question: when listening to the onClick event of a button, then receiving the MouseEvent, what can cause the MouseEvent's toElement property to be null?
I am running this in a browser (chrome and firefox) after compiling to JS.
EDIT:
In the HTML file I linked the compiled JS script directly.
Now I changed to link the dart script and the pakcages/browser/dart.js (as in sameple dart web apps). After this change, it works fine (event.toElement != null) in chromium and chrome, but not in firefox. Firefox still has event.toElement == null
What to do??
CODE:
HTML:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="sample_container_id">
<p id="sample_text_id"></p>
</div>
<script type="application/dart" src="button_event.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
DART:
import 'dart:html';
void main() {
ButtonElement b = new ButtonElement();
b.text = 'Press Me';
b.id = 'button_id';
b.onClick.listen(onMarketButtonClick);
querySelector('#sample_container_id').append(b);
}
void onMarketButtonClick(MouseEvent _event) {
querySelector('#sample_text_id').text = _event.toElement.toString();
}
RESULT:
In Chrome, clicking the button outputs 'button'
In FireFox, clicking the button outputs 'null'
USE CASE:
In the call back (onMarketButtonClick), I want to retrieve the button id and custom attributes of the button that was clicked, such that I can identify which button was clicked.
Imagine a calculator app. Buttons of different numbers have different inner-html's and different custom attributes and/or ids. But all have the same onClick listener.
When the listener is called, I need to identify which number was clicked. So I need access to the ButtonElement and its custom attributes and id and inner html etc.
(custom attributes for more complex use cases than the calculator)
Thanks a lot,
Imran
The Firefox property is called relatedEvent. Use that, and you won't get null.
I'm still not sure of the use case, but depending on what information you wanted, you could probably just use currentTarget or target:
querySelector('#sample_text_id').text = _event.currentTarget.toString();
querySelector('#sample_text_id').text = _event.target.toString();
You can basically use EventTarget target property of MouseEvent (link). Here is a basic example:
import "dart:html";
void main() {
document.body.append(new ButtonElement()..text="btn1"..id="btn1");
document.body.append(new ButtonElement()..text="btn2"..id="btn2");
document.onClick.listen((MouseEvent e) => (print(e.target.id)));
}
Whenever, mouse clicks you can check the type of target, which is button for your case. Then, you can do whatever you want with it.

How to get the radiobutton for corresponding datalisty item?

I want to convert this code to JavaScript code:
rdb1 = (RadioButton)DataList1.Items[i].FindControl("rdb1");
How can it be done?
Put a unique class on the radio button and then you can easily use jQuery to walk the DOM and find that control.
Here is an example of finding a control here on Stack Overflow.
Here is a tutorial of How to Get Anything You Want from a web page via jQuery.
Good luck, and hope this helps.
In JavaScript using the id attribute makes it easy to retreive a specific element since the id must be unique for all tags.
var radio1= document.getElementById("rdb1"); //this returns the element
Here is a simple tutorial on how to do other things after getting the element.
EDIT- I see you just want the selected value in javascript:
function radiochanged(){
var radio1= document.getElementById("rdb1");
var rdb1_value;
for (i=0;i<radio1.length;i++)
{
if (radio1[i].checked)
{
rdb1_value = radio1[i].value;
}
}
}
<input id="rdb1" type="radio" onClick="radiochanged()">

Javascript checkboxes with <asp:checkbox />

The Javascript checkbox script (by ryanfait) worked beautifully when I used it at first. Then I needed to alter the form I made so that asp.net could process the form, but now the checkboxes are default.
Is there a way to alter the script to make it work on the asp:checkbox?
I call the function like so:
$(document).ready(function() {
$('input[type=checkbox]').checkbox();
});
And here is the actual javascript.
I have two different types of checkboxes on my page at the moment, one <asp:Checkbox ... /> and one <input type="checkbox" ... />. The second one gets styled, the asp checkbox doesn't...
I haven't contacted Ryan Fait yet, as I hoped this was a common "bug".
EDIT:
The way the script works is, it finds all elements with class="styled", hides it and then puts a span next to the element. Somehow in my sourcecode, for the asp:checkbox this happens too early I think. Look:
<input type="checkbox" class="styled" /><span class="styled"><input id="ctl00_contentPlaceHolderRightColumn_newsletter" type="checkbox" name="ctl00$contentPlaceHolderRightColumn$newsletter" /></span>
The span is there, visible and all, which it should not (I believe, as the first checkbox shows up in the style I want it to be, the second doesn't).
So far, I found a part of the problem. The javascript cannot change the asp checkbox somehow, but when I manually add the span the javascript is supposed to create, the checkbox doesn't work as a checkbox anymore. I added some details in my answer below.
Set an ID on your checkbox and then reference it by that ID, like so:
<asp:checkbox id="mycheck" />
Then reference it like this:
$('#mycheck').checkbox();
If that doesn't work, do what many, many web developers before you have done: download Firefox, install Firebug, and check your selector logic in the console. I find it's always easier to develop in Firefox, even when my target platform is IE.
I found part of the answer.
When I add the span the plugin creates manually like so:
<span class="checkbox" style="background-position: 0pt 0pt;"><asp:CheckBox ... /></span>
I do get the nicely looking checkbox UNDERNEATH the actual checkbox!
However, the styled box is not interactive. It doesn't change when I click it or hover over it nor does it register the click. It's basically not a checkbox anymore, just a goodlooking square. The actual asp checkbox that shows up does register clicks, but it's the ugly standard one.
<span class="checkbox" style="background-position: 0pt 0pt;"><asp:CheckBox ID="anId" runat="server" style="visibility: hidden;" /></span>
The visibility: hidden makes the "real" checkbox dissappear and leaves the goodlooking yet broken one.
Got it.
Forget about the RyanFait Solution, this one works on ALL checkboxes. :D
var boxes;
var imgCheck = 'Images/checkbox-aangevinkt.png';
var imgUncheck = 'Images/checkbox.png';
function replaceChecks(){
boxes = document.getElementsByTagName('input');
for(var i=0; i < boxes.length; i++) {
if(boxes[i].getAttribute('type') == 'checkbox') {
var img = document.createElement('img');
if(boxes[i].checked) {
img.src = imgCheck;
} else {
img.src = imgUncheck;
}
img.id = 'checkImage'+i;
img.onclick = new Function('checkChange('+i+')');
boxes[i].parentNode.insertBefore(img, boxes[i]);
boxes[i].style.display='none';
}
}
}
function checkChange(i) {
if(boxes[i].checked) {
boxes[i].checked = '';
document.getElementById('checkImage'+i).src=imgUncheck;
} else {
boxes[i].checked = 'checked';
document.getElementById('checkImage'+i).src=imgCheck;
}
}
I think that your problem could be caused by the fact that asp:CheckBox controls are automatically wrapped in a span tag by default, and setting the CssClass attribute on the asp:CheckBox control actually adds the class to the span (not the input) tag.
You can set the class on the input tag using the 'InputAttributes' as follows:
chkMyCheckbox.InputAttributes.Add("class","styled");
...
<asp:checkbox id="chkMyCheckbox" />
This should then allow you to target the checkbox with your existing JavaScript.
You don't need to use the 'type' attribute. Does the following work for you?
$(document).ready(function() {
$('input:checkbox').....etc
});

Way to update css properties on-the-fly based on form content?

I have a form on a website, in which one of the inputs is to be used to enter hexadecimal colour codes to be entered into a database.
Is there any way for the page to dynamically update itself so that if the user changes the value from "000000" to "ffffff", the "colour" CSS property of the input box will change immediately, without a page reload?
Not without Javascript.
With Javascript, however...
<input type='text' name='color' id='color'>
And then:
var color = document.getElementById('color');
color.onchange = function() {
color.style.color = '#' + this.value;
}
If you are going to go the Javascript route, though, you might as well go all out and give them a color picker. There are plenty of good ones.
CSS properties have corresponding entries in the HTML DOM, which can be modified through Javascript.
This list is somewhat out of date, but it gives you some common CSS pieces and their corresponding DOM property names.
Granted, a JS lib like like jQuery makes this easier...
You can use Javascript to achieve that.
As an example:
Your HTML:
<input type="text" id="test" />
Your JS:
var test = document.getElementById('test');
test.onchange = function(){
test.style.color = this.value;
};
But this doesn't check the user's input (So you would have to extend it).

Resources