I would like to 'toggle' the list of options in a select box.
I have the two sets of options as strings (American states and Canadian Provinces). However, I notice that in the DOM, the select object has no 'innerhtml' property (at least not according to w3schools).
Do I have to go and remove and replace the options one by one? How do I do this?
Making use of jQuery, I usually do something like this:
var html = '[your html string with all the options elements]';
$('#mySelectId').empty();
$('#mySelectId').append(html);
As for the one-by-one idea, make sure you keep in mind the general slowness of DOM interaction. Wholesale replacement with the entire string is going to be pretty quick, but if you manipulate the DOM for each element in the select then expect it to be slow.
What I would do is create both, each in a DIV; then just hide whichever is not needed. This eliminates the need for heavy DOM manipulation (as you're only doing that once, on page load, there are fewer opportunities to leak memory in certain browsers cough cough), and is harder to accidentally mess up the app state (what with Alberta and Alabama sharing the same code and all that).
This would be the initial page:
<input type="radio" id="country_usa" name="country" value="USA"> USA
<input type="radio" id="country_canada" name="country" value="Canada"> Canada
<div id="usa_select"></div>
<div id="canada_select"></div>
and JavaScript to go with it (jQuery used here for brevity):
$(document).ready(function(){
// hide both <div> containers on page load
$('#canada_select').hide();
$('#usa_select').hide();
// create and populate both <select> boxes:
$('#canada_select').append('<select name="province_canada">'
+ '<option value="AL">Alberta</option>'
+ '<option value="BC">British Columbia</option>...'
+ '</select>'
);
$('#usa_select').append('<select name="state_usa">'
+ '<option value="AL">Alabama</option>'
+ '<option value="AK">Alaska</option>...'
+ '</select>'
);
};
// we'll also need handlers to show the correct list,
// depending on the selected country
$('#country_usa').click(function(){
// we want US states
$('#canada_select').hide();
$('#usa_select').show();
});
$('#country_canada').click(function(){
// we want Canadian provinces
$('#usa_select').hide();
$('#canada_select').show();
});
This should be the result:
<input type="radio" id="country_usa" name="country" value="USA"> USA
<input type="radio" id="country_canada" name="country" value="Canada"> Canada
<div id="usa_select">
<select name="state_usa">
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
...
</select>
</div>
<div id="canada_select">
<select name="province_canada">
<option value="AL">Alberta</option>
<option value="BC">British Columbia</option>
...
</select>
</div>
At the backend, process state_usa iff country=='USA'; process province_canada iff country=='Canada'.
Why not replace the entire <SELECT>? There are a number of ways to do this. Easiest is to wrap the <SELECT> in a SPAN/DIV and replace its innerHTML.
If you're pulling your lists from an array, you can set the list length to zero, then insert the new elements in a loop.
When you say they are held as strings - do you mean that each item is a seperate string or that the list items are one string (i.e. var variable = "<li>item 1</li><li>item 2</li>";)
If the latter, could you not include the <select> tag in the string and use the jQuery replaceWith function?
Just add a multiple="multiple" attribute to your select tag if you want multiple selection or add size=".." if you want single selection
Related
I'm just starting with Angular JS and i find it very handy in terms of data handling.
My question, is it possible to bind a custom attribute by html alone? Specifically with the select element.
Instead of getting the value attribute, i want to get a custom attribute from the option tags under select element.
Just to be clear, instead of displaying the "value" of the input element, i want to display what's inside the data-custom1 which is the word "payment".
Example would be:
<select ng-model="colors">
<option data-color-hex="#2ba2ba" value="1"> Color A<option>
<option data-color-hex="#222222" value="2"> Color B<option>
<option data-color-hex="#cacaca" value="3"> Color X <option>
</select>
<p>{{display the data-color-hex value here}} </p>
If i select an option from the select element, the data-color-hex is displayed
in the element instead of value 1,2,3.
You first need to set a name for your select:
<select name="colors" ng-model="$ctrl.colors">
<option value="1" data-custom1="paymentA">1</option>
<option value="2" data-custom1="paymentB">2</option>
<option value="3" data-custom1="paymentC">3</option>
</select>
Then, you can create a method in your ctrl which returns the data-custom1 attribute from the selected option:
$ctrl.getDataCustomFromSelect = function(selectName) {
return document.querySelector('select[name="' + selectName + '"] option:checked')
.getAttribute('data-custom1');
}
You can get that in your template doing:
<p ng-bind="$ctrl.getDataCustomFromSelect('colors')"><p>
Fiddle with that solution: https://jsfiddle.net/virgilioafonsojr/b002ccja/
I hope I understood your problem correctly and it solves the issue.
Two ways to do this, and you'll probably want to use the first:
<input ng-model="amount" data-custom1="{{payment}}">
<p>{{payment}}<p>
Or by using ngAttr:
<input ng-model="amount" ng-attr-payment="{{payment}}">
<p>{{payment}}<p>
The latter one is used for picky DOM APIs like the SVG DOM API. You can read more here: https://docs.angularjs.org/guide/interpolation
If you want get the input value, you have to use ng-model, only this.
And then, in your controller.js, get the input value from ng-model.
(I don't know if that's what you want to know)
Basic Problem
I have a multi-select (list) that depending on how I write the html/angular has a bug. In the first case the last 3 characters are cut off from the rendering. In the second case the name is not visible but instead the {{}} placeholder until the item is clicked.
I'd simply like a way for me to display the elements in a correct fashion without bugs.
Finally, this behavior seems to happen if an element is added to the categories array after the page and select has rendered.
With ng-bind
<select id="categories" name="categories" class="ep_field sumoSelect" multiple="multiple"
ng-model="selectedCategories"
ng-change="angularCategorySelectedGrants($event)"
<option ng-repeat="cat in categories" value="{{cat.id}}" ng-bind="cat.name"></option>
</select>
Without ng-bind
<select id="categories" name="categories" class="ep_field sumoSelect" multiple="multiple"
ng-model="selectedCategories"
ng-change="angularCategorySelectedGrants($event)"
<option ng-repeat="cat in categories" value="{{cat.id}}">{{cat.name}}</option>
</select>
With ng-options
With ng-options everything appears but I am unable to actually click on the elements to select them - they are frozen.
<select id="categories" name="categories" class="ep_field sumoSelect" multiple="multiple"
ng-model="selectedCategories"
ng-change="angularCategorySelectedGrants($event)"
ng-options="cat.name for cat in categories track by cat.id" >
</select>
Since no-one wrote an answer, see my own work-around as the accepted answer.
My own workaround
It seems the problem was with adding an item to the categories array after the initial rendering has taken place. There we two workarounds I found:
Add all elements to the array only once without adding again OR
Hide the dom select element utilizing ng-if for 100ms and make it visible again. This forces the browser to re-render the elemnents and renders them correctly.
In HTML (wrapping the select):
<div ng-if="categories!=undefined && categoriesLoaded">
...Select code here...
</div>
In the controller (Javascript):
$scope.categoriesLoaded = false;
//Trigger render
$timeout(function(){ $scope.categoriesLoaded = true;}, 0);
Here is the code
<form method="get" name="form_delivery">
Please select country for delivery<br>
<select name="deliverymethod">
<option value="0" selected="selected">Select country / region</option>
<option value="1">UK (incl. Northern Ireland)</option>
<option value="8">Australia</option>
<option value="9">New Zealand</option>
</select>
</form>
I need to identify the text "Please select country for delivery" and wrap it around the container like a "span" and replace the wrapped text
<form method="get" name="form_delivery">
<span>Please select country for delivery</span><br>
This code is generated by an automated server, I only have access to HTML Template hence Jquery is the only option for making modifications on the fly.
Any Idea's?
Two solutions here :
1 : If you don't have any binding on other elements of the form, you may simply do a replace of the HTML :
$('form').html(function(_,h){
var t = "Please select country for delivery";
return h.replace(t, '<span>'+t+'</span>');
});
2 : If you have bindings, you can't do that as it would delete all elements, you need to do it cleanly, not modifying other elements. You may use a library for that like my own groumf :
Groumf.replaceTextWithHTMLInHTML(document.body, t, function(s){
return '<span>'+t+'</span>'
});
If you know that the text is the first part of the form, you can use $($('form').get(0).childNodes[0]).wrap('<span>');.
You can use contents() to get the text nodes as well as the HTML elements using jQuery. You can then filter out the text nodes, using .filter() (which might be unnecessary, depending on your potential markup) and then get what I'm assuming will always be the first text node, using .eq().
From there we can wrap this text node in a <span> using .wrap(), traverse to this new <span>, and prepend it to our form:
var $form = $('form[name=form_delivery]')
$form.contents().filter(function(){
return this.nodeType == 3;
}).eq(0).wrapAll('<span></span>').closest('span').prependTo($form);
JSFiddle
So I am trying to use XMLHTTPRequest to get some information from another page. It will have several <option>s, a variable number of them.
My thoughts were that I could get all of these options, outputted as text, and insert them wholesale into the select menu. Would this be possible? An example of what I want to do:
<select name="culture[]" onSubmit="formValidation()" multiple="multiple" id="cultpicklist"></select>
is the select menu, and then I would do something like this (pseudo-code)
txtobjfromXMLHTTPRequest would be this:
<option value="41" name="culture[]">testculthy</option>
<option value="47" name="culture[]">ereeevvv</option>
<option value="49" name="culture[]">yep</option>
<option value="50" name="culture[]">addanother</option>
txtObj = txtobjfromXMLHTTPRequest //to shorten what I have to write/what you have to read
document.getElementById("cultpicklist").value(txtObj)
Would this work? Am I on the right path? How should I change this?
You should try using .innerHTML:
document.getElementById("cultpicklist").innerHTML = txtObj;
You should however thoroughly test this in all the browsers you support, as there are some cross browser issues with this.
...and here's the fiddle: http://jsfiddle.net/5PGF6/
I tried using $('.className').show(); and $('.className').hide(); but it doesn't seem to work in IE. Is there another way to group options by class in a drop down list? I found this question but the answer is looking for the value "a" or "c".
//if 2 is selected remove C
case 2 : $('#theOptions2').find('option:contains(c)').remove();break;
//if 3 is selected remove A
case 3 : $('#theOptions2').find('option:contains(a)').remove();break;
How do I look for the actual class?
EDIT
<select id="theOptions2">
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
I've never seen anyone try to call hide/show on option elements before, and I imagine IE just doesn't allow you to do that. The selection is probably matching just fine, but IE is not hiding the elements. The selection for removing would be the same as for calling show hide...
$('.className').remove();
or
$('option.className').remove();
or
$('#theSelect option.className').remove();
You can add the disabled attribute to the options you don't want to use:
http://jsfiddle.net/sadmicrowave/Fnvqb/
$('select[class~="cactus"]')
$('option[class~="cactus"]')
javascript:(function(){
var out = "hi\n";
out += $('*[class~="cactus"]').html2string() ;
alert( out );
})()
For future reference, instead of describing in words the html ... show actual html
This demonstration code shows one way of how you can achieve option filtering... it would need modification to determine which candidate items are removed as I just hardcoded for purpose of demonstration, but it shows you what you need to consider - when you remove the items, you need to consider the ordering by which they're added back. The easiest way to bypass this problem is to keep a copy of the original list and then when you unfilter, just remove the remaining items, replacing them with what was originally there - otherwise you have to worry about keeping sort data.
So here's my drop down definition:
<select id="mySelector">
<option class="group1">Item 1</option>
<option class="group2">Item 2</option>
<option class="group1">Item 3</option>
<option class="group2">Item 4</option>
<option class="group1">Item 5</option>
</select>
<input type="button" id="removeItems" value="Remove candidate items" />
<input type="button" id="addItems" value="Add them back" />
And the jquery to filter/restore the items:
$(function () {
var originalOptionData;
$("#removeItems").bind('click', function () {
/* store original copy for rollback */
originalOptionData = $("#mySelector option");
$("#mySelector option.group2").remove();
});
$("#addItems").bind('click', function () {
var selector = $("#mySelector");
selector.children().remove();
selector.append(originalOptionData);
});
});
This could be turned into a select filter jquery plugin relatively simply I suppose, but I didn't go that far...