Goal: I want to add setValue and getValue functions to JQueryUI Autocomplete widget.
Assuming an autocomplete list has a datasource of id/label pairs, I want to call to setValue and getValue like this:
// this is how I *want* to call it
$("#tags").autocomplete('setValue', 2); // should select "two" in the list
$("#tags").autocomplete('getValue') // if "two" is selected, it should return 2
Here's the context HTML:
<script>
// if I pass in 2 for the id, it should select "two"
function setValueClick(){
$("#tags").autocomplete('setValue', 2);
}
// if "two" is the selected item, getValue should return 2
function getValueClick(){
console.log($("#tags").autocomplete('getValue'));
}
</script>
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags" /> <br/>
<button onclick="setValueClick()">Set value to 2</button>
<button onclick="getValueClick()">Get value</button>
</div>
and the JS:
$.widget("ui.autocomplete", $.ui.autocomplete, {
setValue: function(id) {
// TODO: make this select the item corresponding to the id param
},
getValue: function(){
// TODO: make this return the id of the selected item
}
});
$(function() {
var availableTags = [
{ id: 1,
label: 'one'
},
{
id: 2,
label: 'two'
},
{
id: 3,
label: 'three'
}
];
$("#tags").autocomplete({
source: availableTags
});
});
And here's a jsfiddle start:
http://jsfiddle.net/spencerw/55jhx/149/
Okay, so I changed things up a little bit, but I feel it's for the better. Feel free to use this in any way you see fit.
You'll notice I added more attributes to the buttons (ele to both and value to the setter). The ele property should be set to the ID of the <input> element you want to modify/retrieve results from. The value property (in the setter) should be set to the id attribute of the availableTags object that you want to show the label of (not the index of the object within the availableTags array). I took out the onclick attributes, and am handling that in the JS, so I could remove the <script> tags from the HTML pane (this is more just to make it a little easier to read in jsFiddle).
Here's the modified HTML:
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags" /> <br/>
<button class='setValueClick' value='2' ele='tags'>Set value to 2</button>
<button class='getValueClick' ele='tags'>Get value</button>
</div>
And the modified JavaScript:
$(document).on('click', 'button.setValueClick', function(){
var ele = $('#' + $(this).attr('ele'));
ele.autocomplete('setValue', $(this).attr('value'));
});
$(document).on('click', 'button.getValueClick', function(){
var ele = $('#' + $(this).attr('ele'));
alert(ele.autocomplete('getValue'));
});
$(function() {
var availableTags = [
{ id: 1, label: 'one' },
{ id: 2, label: 'two' },
{ id: 3, label: 'three' }
];
$.widget("ui.autocomplete", $.ui.autocomplete, {
setValue: function(id) {
var input = $(this.element[0]);
$.each(availableTags, function(k, v){
if(v.id == id){
input.val(v.label);
return false;
}
});
},
getValue: function(){
var val = $(this.element[0]).val(), ret = false;
$.each(availableTags, function(k, v){
if(v.label == val){
ret = v.id;
return false;
}
});
return ret;
}
});
$("#tags").autocomplete({
source: availableTags
});
});
You can see a working, super-documented, version of the answer here:
http://jsfiddle.net/hftn7oqw/
Related
I have a json that returns this:
[
{"home": [
{"name":"Federico","surname":"","et":"20","citt":"Milano"},
{"name":"Alberto","surname":"","et":"30","citt":"Milano"},
{"name":"Mirko","surname":"","et":"30","citt":"Roma"},
{"name":"Andrea","surname":"","et":"28","citt":"Firenze"}
]},
{"home": [
{"name":"Brad Pitt"},
{"name":"Tom Cruise"},
{"name":"Leonardo DiCaprio"},
{"name":"Johnny Depp"}
]},
{"home": [
{"name":"","surname":""},
{"name":"","surname":""},
{"name":"","surname":""},
{"name":"","surname":""}
]}
]
When there is a valid value provided for name, for example, I would like to change the background-color of the input box to white. But if the provided value is invalid, I would like to change the background-color back to red.
HTML:
<div class="context">
<div data-bind="foreach: personList">
<button data-bind="text: name,click: $root.getInfoPersona($index()), attr: {'id': 'myprefix_' + $index()}"/>
<button data-bind="text: $index,enable: false"></button>
</div>
<form>
<label>Name: </label>
<input id="idname" data-bind="value: name, css: { changed: name.isDirty(), notchanged : !name.isDirty() }" />
<label>Surname: </label>
<input id="idsurname" data-bind="value: surname, css: { changed: surname.isDirty }" />
<label>Years: </label>
<input id="idyears" data-bind="value: years, css: { changed: years.isDirty }" />
<label>Country: </label>
<input id="idcountry" data-bind="value: country, css: { changed: country.isDirty }" />
<button data-bind="click: save">Save Data</button>
<button data-bind="click: clear">Clear</button>
</form>
</div>
Javascript:
$(document).ready(function(){
ko.subscribable.fn.trackDirtyFlag = function() {
var original = this();
this.isDirty = ko.computed(function() {
return this() !== original;
}, this);
return this;
};
var ViewModel = function() {
var self=this;
var pi= (function(){
var json = null;
$.ajax({
'async': false,
'global': false,
'url': 'persona.json',
'dataType': 'json',
'success': function(data){
json=data;
}
});
return json;
})();
var questionsPerson= pi;
console.log(questionsPerson);
self.personList = ko.observableArray(questionsPerson[0].home);
var n=pi[0].home[0].name;
var c=pi[0].home[0].surname;
var e=pi[0].home[0].et;;
var ci=pi[0].home[0].citt;
self.name = ko.observable(n).trackDirtyFlag();
self.surname = ko.observable(c).trackDirtyFlag();
self.years = ko.observable(e).trackDirtyFlag();
self.country = ko.observable(ci).trackDirtyFlag();
self.save = function() {
alert("Sending changes to server: " + ko.toJSON(self.name));
alert("Sending changes to server: " + ko.toJSON(this));
};
self.clear = function(){
self.name("");
self.surname("");
self.years("");
self.country("");
};
self.getInfoPersona = function(indice){
var i=indice;
var ris= pi;
var n=ris[0].home[indice].name;
var c=ris[0].home[indice].surname;
var e=ris[0].home[indice].et;
var ci=ris[0].home[indice].citt;
self.name(n);
self.surname(c);
self.years(e);
self.country(ci);
self.getinfoPersona = ko.computed( function(){
return self.name() + " " + self.surname() + " " + self.years() + " " + self.country();
});
};
};
ko.applyBindings(new ViewModel());
});
First screenshot: the desired effect.
Second screenshot: the wrong effect.
The effect displayed on the second screenshot happens when I click on the second name to change person. The input box becomes "invalid" with background-color=red instead of background-color=white.
The quickest way to get it working is to modify your trackDirtyFlag extension:
ko.subscribable.fn.trackDirtyFlag = function() {
var original = ko.observable(this()); // make original observable
this.isDirty = ko.computed(function() {
return this() !== original(); // compare actual and original values
}, this);
// this function will reset 'dirty' state by updating original value
this.resetDirtyFlag = function(){ original(this()); };
return this;
};
...and call resetDirtyFlag after you reassigned values for editing:
self.name(n); self.name.resetDirtyFlag();
self.surname(c); self.surname.resetDirtyFlag();
self.years(e); self.years.resetDirtyFlag();
self.country(ci); self.country.resetDirtyFlag();
Look at the fiddle to see how it works.
However in general your approach is pretty far from optimal. Maybe this article will be useful for you.
I m trying to implant one function to display name (not value) of checkbox when they are selected. I m on Ruby on Rail app.
So my jquery code is
<script type="text/javascript">
$(document).ready(function () {
$('input[name="animaux"]').click(function () {
getSelectedCheckBoxes('animaux');
});
$('input[name="handicap"]').click(function () {
getSelectedCheckBoxes('handicap');
});
$('input[name="television"]').click(function () {
getSelectedCheckBoxes('television');
});
$('input[name="barbecue"]').click(function () {
getSelectedCheckBoxes('barbecue');
});
var getSelectedCheckBoxes = function (groupName) {
var result = $('input[name="' + groupName + '"]:checked');
if (result.length > 0) {
var resultString = "";
result.each(function () {
var selectedValue = $(this).val();
resultString += groupName + " - "
+ $('label[for="option-' + selectedValue + '"]').text() + "<br/>";
});
$('#divfilter').html(resultString);
}
else {
$('#divfilter').html("");
}
};
});
</script>
Filters are displayed with
<div id="divfilter"></div>
And checkbox look like this
<input type="checkbox" name="barbecue" id="barbecue" value="oui" class="barbecue" />
<input type="checkbox" name="handicap" id="handicap" value="oui" class="handicap" />
<input type="checkbox" name="animaux" id="animaux" value="oui" class="animaux" />
Question 1 :
When i select one checkbox thats works. But if i select 2 checkbox the first label name is replace by the new one. I want those 2 labels. How i can do that ?
Question 2:
Any idea to simplified and DRY this ?
$('input[name="animaux"]').click(function () {
getSelectedCheckBoxes('animaux');
});
$('input[name="handicap"]').click(function () {
getSelectedCheckBoxes('handicap');
});
$('input[name="television"]').click(function () {
getSelectedCheckBoxes('television');
});
$('input[name="barbecue"]').click(function () {
getSelectedCheckBoxes('barbecue');
});
Question 3 :
Any idea to implant a cross for "unselect" between the name ?
Thanks for your help !
By the way sorry for my bad english I m french...
I'd suggest:
// find and retrieve all <input> elements of
// 'type=checkbox':
var checkboxes = $('input[type=checkbox]');
// use the on() method to bind the anonymous function
// as the event-handler of the 'change' event:
checkboxes.on('change', function(){
// update the '#divfilter' element's text:
$('#divfilter').text(function(){
// we return the following as the new text:
// first we filter the checkboxes collection to
// retain only those that match the ':checked'
// pseudo-class, and then create a map:
return checkboxes.filter(':checked').map(function(){
// the contents of the map are comprised of
// the 'name' property of each checked check-box:
return this.name;
// we convert the map() into an Array, using get():
}).get()
// and join the Array elements together with the
// supplied String, and finished with a period:
.join(', ') + '.';
});
});
// find and retrieve all <input> elements of
// 'type=checkbox':
var checkboxes = $('input[type=checkbox]');
// use the on() method to bind the anonymous function
// as the event-handler of the 'change' event:
checkboxes.on('change', function() {
// update the '#divfilter' element's text:
$('#divfilter').text(function() {
// we return the following as the new text:
// first we filter the checkboxes collection to
// retain only those that match the ':checked'
// pseudo-class, and then create a map:
return checkboxes.filter(':checked').map(function() {
// the contents of the map are comprised of
// the 'name' property of each checked check-box:
return this.name;
// we convert the map() into an Array, using get():
}).get()
// and join the Array elements together with the
// supplied String, and finished with a period:
.join(', ') + '.';
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" name="barbecue" id="barbecue" value="oui" class="barbecue" />
<input type="checkbox" name="handicap" id="handicap" value="oui" class="handicap" />
<input type="checkbox" name="animaux" id="animaux" value="oui" class="animaux" />
<div id="divfilter"></div>
JS Fiddle.
References:
CSS:
Attribute selectors.
JavaScript:
Array.prototype.join().
jQuery:
filter().
get().
map().
on().
text().
I have multiple checkbox, when i check a checkbox two key value pair will generate.
Like this : Object {id: "101", name: "example"}
This will generate for every checkbox checked and i want for multiple checkbox checked array. look like this :
[{id:"id1",name:"name1"},{id:"id2",name:"name2"}]
What I have done
$('.chkCompare').click(function(event) {
var value = [],
projectName = {},
span = $(this).attr('id'),
value = $('.chkCompare:checked').map(function() {
$('#span' + span).text('ADDED').css({
"color": "green"
});
projectName['id'] = $(this).attr('id');
projectName['name'] = $(this).attr('title');
return value.push(projectName);
}).get();
});
When I uncheck checkbox they will be remove from array and want to prevent check maximum 3 checkbox if >3 then show an alert box.
You can check the length property of :checked checkbox's. Based on your condition and use event.preventDefault() to cancel the default action.
$('.chkCompare').click(function(event) {
var checkedElemets = $('.chkCompare:checked');
if (checkedElemets.length > 3) {
event.preventDefault();
alert('Only 3 checkbox can be checked');
}
var values = checkedElemets.map(function() {
return {
id: this.id,
name: this.title
};
}).get();
console.log(values)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" class="chkCompare" title='t1' id='i1' />
<input type="checkbox" class="chkCompare" title='t2' id='i2'/>
<input type="checkbox" class="chkCompare" title='t3' id='i3'/>
<input type="checkbox" class="chkCompare" title='t4' id='i4'/>
<input type="checkbox" class="chkCompare" title='t5' id='i5'/>
$("input[type='checkbox']").change(function(){
var arr = {};
var count = 0;
$.each($("input[type='checkbox']:checked"), function(){
if(count++<3){
arr[this.id] =this.name;
}else{
$(this).prop('checked', false);
}
});
console.log(JSON.stringify(arr));
});
I have an issue with jsviews. I want to bind an array of elements. Each element is an object. Elements are added dynamicaly. Value of one field of each element computes base on another field. How is it posiible to do without refreshing array every time?
js:
model = {
elements: []
};
$(function() {
$.when($.templates('#tmpl').link('#container', model)
.on('click', '#addElement', function () {
$.observable(model.elements).insert({});
})
).done(function() {
$.observe(model, 'elements', function(e, eventArgs) {
if (eventArgs.change === 'insert') {
eventArgs.items.forEach(function(addedElement) {
$.observe(addedElement, 'value1', function(e) {
var element = e.target;
element.value2 = 'Value1 is ' + element.value1;
$.observable(element).setProperty('value2', element.value2);
$.observable(model).setProperty('recent', element.value1);
});
});
}
});
});
});
html:
<div id="container"></div>
<script id="tmpl" type="text/x-jsrender">
<input id="addElement" type="button" value="add new element"/>
<div id="box">
{^{for elements tmpl="#elementTmpl"/}}
</div>
<input type="text" data-link="recent" />
</script>
<script id="elementTmpl" type="text/x-jsrender">
<div>
<input name="input1" data-link="value1" />
<input name="input2" data-link="value2" />
</div>
</script>
I created jsfiddle that illustrates the problem.
You can use ObserveAll(): http://www.jsviews.com/#observeAll.
Every time the element.value1 changes, you update the calculated properties element.value2 and model.recent.
I updated your fiddle here https://jsfiddle.net/1rjgh2sn/2/ with the following:
$.templates('#tmpl').link('#container', model)
.on('click', '#addElement', function () {
$.observable(model.elements).insert({});
});
$.observable(model).observeAll(function(e, eventArgs) {
if (eventArgs.change === "set" && eventArgs.path === "value1") {
var element = e.target;
$.observable(element).setProperty('value2', 'Value1 is ' + element.value1);
$.observable(model).setProperty('recent', element.value1);
}
});
I can't figure out how to retrieve the current attr. value of the input type range element.
The attr. value seems not be the 'internal attr. value' which is changed during slides.
Javascript
'use-strict';
(function(){
var fooProt = Object.create(HTMLElement.prototype);
Object.defineProperty(fooProt, "bar", {
value: {test: 1},
writable: false,
enumerable: true
});
fooProt.getMin = function() {
return this.bar.test;
};
fooProt.attachedCallback = function () {
this.addEventListener('change', function(){
//get current value, following does not appear to work
//console.log(this.value);
});
};
var foo = document.registerElement('ex-foo', {prototype : fooProt, extends : 'input'});
})();
Html
<input type="range" min="1" max="100" value="1" is="ex-foo" id="foo">
HTMLElement doesn't provide you with a value property, but HTMLInputElement does:
var fooProt = Object.create(HTMLInputElement.prototype);