I am using jquery-select2 (4.0.0). The issue is when I select an option, then select another option, item.selected remains true for both options - FOREVER. Is there some initial config option I am missing or is this a bug?
function formatResult(item) {
console.log("item selected = ", item.selected);
return item.text;
}
$('select').select2({
templateResult: formatResult,
minimumResultsForSearch: Infinity,
placeholder: "Please choose",
multiple: false,
maximumSelectionSize: 1
});
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.js"></script>
<select>
<option></option>
<option>conan</option>
<option>kimmel</option>
<option>stewart</option>
<option>colbert</option>
</select>
I should start this off by saying that item.selected (the selected property of the data object) is not documented, and will change in the future. Why do I say it will? Because this bug only occurs on single select elements (as explained at the very end), but you can safely ignore it for now.
Right now the item.selected property is only used by Select2 on <input /> elements, and the item.element.selected property is used for <select> elements. This will always be your source of truth when using a <select> element, as item.element is a reference to the <option> element that your browser uses for determining what data should be sent to the server.
You can see after looking at item.element.selected that it is correctly updated when the selection changes.
function formatResult(item) {
console.log("item selected = ", item.selected);
console.log("item.element.selected = ", item.element && item.element.selected);
return item.text;
}
$('select').select2({
templateResult: formatResult,
minimumResultsForSearch: Infinity,
placeholder: "Please choose",
multiple: false,
maximumSelectionSize: 1
});
<link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.js"></script>
<select>
<option></option>
<option>conan</option>
<option>kimmel</option>
<option>stewart</option>
<option>colbert</option>
</select>
And yes, the item.selected property will be fixed in the future so it is accurate. Right now it is not updated because in a single select, new options are selected and those implicitly unselect the old options. This is unlike a multiple select, where options are explicitly selected and unselected.
Related
I have configured my select via select2 and things works quite well.
I have used templateResult with formatState approach to add the icon to my dropdown options.
$(".js-country-list").select2({
templateResult: formatState
});
that however does not change anything to selected value (see image below).
How can I make sure that selected value (in my case EUR) would be displayed exactly same as option: Euro (EUR)?
Thanks.
The templateSelection method described at https://select2.org/selections can be used to achieve this, it can be passed the same function used by templateResult.
$(".js-country-list").select2({
templateResult: formatState,
templateSelection: formatState
});
Example listing countries and their flags (not currencies) is incorporated below.
// Template function which adds CSS flag and displays country name
function flagTemplate(country){
return $("<span class='flag-icon flag-icon-" + country.id + " '></span><span class='flag-text'>" + country.text + "</span>");
}
// Generate correct URL based on entered search term
function generateUrl(params){
if(params.term){
return "https://restcountries.com/v3.1/name/" + params.term;
} else {
return "https://restcountries.com/v3.1/all";
}
}
// Initialise select2 using flagTemplate function for both result and selection
$('#countrySelect').select2({
// Set template for results and selection
templateResult: flagTemplate,
templateSelection: flagTemplate,
// Set placeholder text
placeholder: 'Select country...',
// Load country list from https://restcountries.com
ajax: {
url: generateUrl,
cache: 250,
dataType: "json",
processResults: function(data) {
return {
results: data
.map(x => ({id: x.cca2.toLowerCase(), text: x.name.common}))
.sort((a, b) => ('' + a.text).localeCompare(b.text))
};
}
}
});
#countrySelect {
width: 300px;
}
.flag-text {
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/js/select2.min.js"></script>
<!-- Load flags using library https://github.com/lipis/flag-icons -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/4.1.5/css/flag-icons.min.css" rel="stylesheet"/>
<select id="countrySelect"><option></option></select>
If I create an observer for all changes on a structure object, the observer will get called unless the the binding is a change to a value in a computed binding.
Is this the expected behavior? If so, how can I capture changes to the property in the computed binding?
Example:
<link rel="import" href="../../bower_components/paper-input/paper-input.html">
<dom-module id="binding-test">
<template>
<paper-input label="Not computed" value="{{myObject.prop1}}"></paper-input>
<paper-input label="Computed" value="{{computeIt(myObject.prop2)}}"></paper-input>
</template>
<script>
Polymer({
is:"binding-test",
properties: {
myObject: {
type: Object,
notify: true,
value: {
prop1: 1,
prop2: 2
}
}
},
observers: [
'somethingChanged(myObject.*)'
],
somethingChanged: function(changeRecord) {
// This code is never executed when the Computed input field is changed
console.log(changeRecord);
},
computeIt: function(value) {
return value;
}
});
</script>
</dom-module>
I could be wrong with this one but I think computed binding is one-way, same as computed property.
If you really want to notify the change on a paper-input like that, you can listen to the value-changed event and then do a notifyPath/set on "myObject.prop2".
<paper-input label="Computed" on-value-changed="valueChanged" value="{{computeIt(myObject.prop2)}}"></paper-input>
valueChanged: function(e) {
this.set("myObject.prop2", e.detail.value);
}
Check out this plunker.
Update
I think there's a better solution for your problem. Instead of converting values back and forth using expressions/filters, paper-input now allows you to define prefix and suffix like the following -
<paper-input label="revenue" type="number">
<div prefix>$</div>
</paper-input>
<paper-input label="email">
<div suffix>#email.com</div>
</paper-input>
You can even define complex inputs like this (you will need to create your own date-input element though) -
<paper-input-container auto-validate>
<label>Social Security Number</label>
<ssn-input class="paper-input-input"></ssn-input>
<paper-input-error>SSN invalid!</paper-input-error>
</paper-input-container>
Code samples above are taken from here. You can read more about it on Polymer's official website over here.
I was trying to write a simple directive to generate a (potentially) more complex dom element. I am quite confused about what is going on here but I think the directive I use inside my directive get linked first? Anyway the element I am generating is not visible where it should.
Sorry for all that confusion, here is the plunkr:
http://plnkr.co/edit/vWxTmA1tQ2rz6Z9dJyU9?p=preview
I think the directive I use inside my directive get linked first?
Yes. A child directive's link function will execute before the parent's link function.
Here is a fiddle that shows two nested directives,
<div d1>
<div d2></div>
</div>
and it logs when the directives' controller and link functions are called.
There are a few issues with your Plunker:
Since you are using # for your isolate scopes, you need to use {{}}s in your attribute values:
<visible value='{{visible}}'>plop</visible>
<invisible value='{{visible}}'>plop</invisible>
Since $scope.visible is defined in your controller, I assume you meant to use that value, and not test.
In the invisible directive, you need to use isolate scope property value in your link function. Property visible is available to the transcluded scope (which is in affect if you use a template in your directive like #Langdon has) but not the isolate scope, which is what the link function sees.
var template = "<span ng-show='value'>{{value}}</span>";
Plunker.
If you want a simple directive, you're better off letting Angular do most of the work through ngTransclude, and $watch.
http://plnkr.co/edit/xYTNIUKYuHWhTrK80qKJ?p=preview
HTML:
<!doctype html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<title>trying to compile stuff</title>
<script src="http://code.angularjs.org/1.1.1/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="AppCtrl">
<input type="checkbox" ng-model="test" id="test" /><label for="test">Visibility (currently {{test}})</label>
<br />
<br />
<visible value='test'>visible tag</visible>
<invisible value='test'>invisible tag</invisible>
</div>
</body>
</html>
JavaScript:
angular
.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.test = false;
})
.directive('visible', function() {
return {
restrict: 'E',
transclude: true,
template: '<span ng-transclude></span>',
replace: true,
scope: {
value: '='
},
link: function(scope, element, attrs) {
console.log(attrs);
scope.$watch('value', function (value) {
element.css('display', value ? '' : 'none');
});
console.log(attrs.value);
}
};
})
.directive('invisible', function() {
return {
restrict: 'E',
transclude: true,
template: '<span ng-transclude></span>',
replace: true,
scope: {
value: '='
},
link: function(scope, element, attrs) {
scope.$watch('value', function (value) {
element.css('display', value ? 'none' : '');
});
}
};
});
I have a search page and want to add some filters to it, my setup is quite simple, I have a CombobBox for Countries and a ComboBox for States.
I want to show ALL the states if no country is selected(actually, the first item of the countries combobox is "All") here is my code:
#(Html.Telerik().ComboBoxFor(m => m.Country)
.Name("cbxCountry")
.BindTo(this.Model.CountryList)
.SelectedIndex(0).CascadeTo("cbxStates"))
#(Html.Telerik().ComboBoxFor(m=>m.State)
.Name("cbxStates")
.DataBinding(binding => binding.Ajax()
.Select("AjaxLoadStates","States")))
Note that even if the .SelectedIndex is set to 1, 3, 1231231 the second combobox keeps disabled until I select a value. Is there any way to make this work?
You can do this with the client API in javascript:
<script type="text/javascript">
function SelectFirstCountry() {
var cbxCountry = $("#cbxCountry").data('tComboBox')
var cbxStates = $("#cbxStates").data('tComboBox')
cbxCountry.select(1);
cbxStates.enable();
}
$(document).ready(function () {
#{
Html.Telerik().ScriptRegistrar().OnDocumentReady("SelectFirstCountry()");
}
});
</script>
I'm attempting to create an accordion where I can expand/collapse all sections with a single click. I also need the ability for the user to open and close the sections having 0-n sections open at a time. Using several of the discussions here on stackoverflow and on jquery forums, here's the solution i've come up with:
I've implemented each section as it's own accordion, where each is set to collapsible = true.
<html>
<head>
<title>Accordion Test</title>
<script type="text/javascript" src="../scripts/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="../scripts/jquery-ui-1.8.4.custom.min.js"></script>
<link rel="stylesheet" href="../_templates/css/jquery-ui-1.8.6.custom.css" type="text/css" />
<link rel="stylesheet" href="../_templates/css/jquery.ui.accordion.css" type="text/css" />
</head>
<body>
<a onClick="expandAll()">Expand All</a>
<br>
<a onClick="collapseAll()">Collapse All</a>
<div id="accordion1" class="accord">
<h5>section 1</h5>
<div>
section 1 text
</div>
</div>
<!-- orders section -->
<div id="accordion2" class="accord">
<h5>section 2</h5>
<div>
section 2 text
</div>
</div>
<!-- section 3 -->
<div id="accordion3" class="accord">
<h5>section 3</h5>
<div>
section 3 text
</div>
</div>
<!-- section 4 -->
<div id="accordion4">
<h5>section 4</h5>
<div>
section 4 text
</div>
</div>
</body>
</html>
<script type="text/javascript">
$(function() {
$('#accordion1').accordion({
header: 'h5',
collapsible: true,
autoHeight: false
});
});
$(function() {
$('#accordion2').accordion({
header: 'h5',
collapsible: true,
autoHeight: false,
active: false
});
});
$(function() {
$('#accordion3').accordion({
header: 'h5',
collapsible: true,
autoHeight: false,
active: false
});
});
$(function() {
$('#accordion4').accordion({
header: 'h5',
collapsible: true,
autoHeight: false,
active: false
});
});
</script>
<script type="text/javascript">
$(document).ready(function() {
})
function expandAll() {
alert("calling expandAll");
$("#accordion1, #accordion2, #accordion3, #accordion4")
.filter(":not(:has(.ui-state-active))")
.accordion("activate", 0);
}
function collapseAll() {
alert("calling collapseAll");
$("#accordion1, #accordion2, #accordion3, #accordion4")
.filter(":has(.ui-state-active)")
.accordion("activate", -1);
}
</script>
The problem I'm running into, is when I click the header of an open section, the section is collapsed as expected, but the header still have the "ui-state-focus" class, until I click elsewhere on the page. So what I see in the ui is the header of section just closed has the same background color as my hover effect, until I click elsewhere, and it shifts to the 'default, not focused' color.
In addition, when I use the Collapse All link, all looks great in Firefox. In IE, the last section header has the same hover-focus coloring.
Any suggestions? Do I somehow need to force the accordion to lose focus when it is closed? How would I accomplish that?
After attempting to over-ride my jquery-ui styles on the page, and attempting to hack the accordion javascript to remove the ui-state-focus class, a simple solution came to light.
Because my page is displaying the expected behavior when I click else where on the page, I used blur() to lose focus.
$(document).ready(function() {
// forces lose focus when accordion section closed. IE and FF.
$(".ui-accordion-header").click(function(){
$(this).blur();
});
})
To fix the collapse all issue in IE, I added 1 line to my collapseAll() method.
function collapseAll() {
alert("calling collapseAll");
$("#accordion1, #accordion2, #accordion3, #accordion4")
.filter(":has(.ui-state-active)")
.accordion("activate", -1);
$(".ui-accordion-header").blur();
}
Solution to implement accordion with all open panels. Panels are static and can't be closed.
Do not initialize accordion div with accordion widget!
$("#accordion").addClass("ui-accordion ui-widget ui-helper-reset")
.find('h3')
.addClass("current ui-accordion-header ui-helper-reset ui-state-active ui-corner-top")
.prepend('<span class="ui-icon ui-icon-triangle-1-s"/>')
.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content-active");
this is my answer~ hope its help
for multiple open you can do like this by using existing jquery UI just add in a options beforeActivate:
my code below:
$( "#accordion" ).accordion({
header: "> div > h3",
autoHeight: false,
collapsible: true,
active: false,
beforeActivate: function(event, ui) {
// The accordion believes a panel is being opened
if (ui.newHeader[0]) {
var currHeader = ui.newHeader;
var currContent = currHeader.next('.ui-accordion-content');
// The accordion believes a panel is being closed
} else {
var currHeader = ui.oldHeader;
var currContent = currHeader.next('.ui-accordion-content');
}
// Since we've changed the default behavior, this detects the actual status
var isPanelSelected = currHeader.attr('aria-selected') == 'true';
// Toggle the panel's header
currHeader.toggleClass('ui-corner-all',isPanelSelected).toggleClass('accordion-header-active ui-state-active ui-corner-top',!isPanelSelected).attr('aria-selected',((!isPanelSelected).toString()));
// Toggle the panel's icon
currHeader.children('.ui-icon').toggleClass('ui-icon-triangle-1-e',isPanelSelected).toggleClass('ui-icon-triangle-1-s',!isPanelSelected);
// Toggle the panel's content
currContent.toggleClass('accordion-content-active',!isPanelSelected)
if (isPanelSelected) { currContent.slideUp('fast'); } else { currContent.slideDown('fast'); }
return false; // Cancels the default action
}
});
refer from :jQuery UI accordion that keeps multiple sections open?
and the function collapse and expand
function accordion_expand_all()
{
var sections = $('#accordion').find("h3");
sections.each(function(index, section){
if ($(section).hasClass('ui-state-default') && !$(section).hasClass('accordion-header-active')) {
$(section).click();
}
});
}
function accordion_collapse_all()
{
var sections = $('#accordion').find("h3");
sections.each(function(index, section){
if ($(section).hasClass('ui-state-active')) {
$(section).click();
}
});
}
that's it..
You can try this small, lightweight plugin.
It will have few options available which we can modify as per our requirement.
URL: http://accordion-cd.blogspot.com/