I'm trying to get an object of checkbox names and values. Suppose I have this form:
<form>
<input type="checkbox" name="email" />
<input type="checkbox" name="name" />
<input type="checkbox" name="hi" />
And Assuming that the first and third are checked, I want this obj:
{ email: 1, name: 0, hi: 1 }
Here's what I tried:
$(':checkbox').map(function() { return this.name + '=' + (this.checked ? 1 : 0) } }).get();
And that gives me:
['email=1', 'name=0', 'hi=1']
But I don't know what do to from here.
Am I going about this wrong?
According to the .map() method doco, .map() returns "a jQuery-wrapped array". Given that you want an object you can instead do something like this:
var checkboxes = {};
$(':checkbox').each(function() {
checkboxes[this.name] = this.checked ? 1 : 0;
});
Noting that if you have checkboxes with the same name (which is valid as far as html forms go) then your object will only keep the value of the last checkbox for each name.
Yeah, you're going about this pretty wrong. From your use of '=' it looks like you expect the function to return JavaScript code that is then run using eval. That's not the way JavaScript operates. Since you're concatenating this.name with a string and a number, JavaScript does its implicit type coercion and returns a string from the function, so you get an array of strings.
The .map() function will always return an array; for miscellaneous operations that don't return an array, you should use the generic .each() iterator.
Here is a quick plugin that does what you want.
$.fn.serializeCheckboxes = function() {
var ret = {};
this.each(function(ix,elm) {
ret[elm.name] = elm.checked ? 1 : 0;
});
return ret;
}
Try this:
$('input[type="checkbox"]').each(function() {
var name = $(this).attr('name');
obj[name] = $(this).is(':checked') ? 1 : 0;
});
http://jsfiddle.net/T7fja/1/
You can try setting the properties using the associative array syntax: ob["property"] = ...
See this working fiddle: http://jsfiddle.net/tuando/JwYFz/
Related
I am using VueJS and trying to use v-model. to connect checkboxes to values in an object:
jobsChecked: {Baker: false, Cook: false, Miner: false} // etc...
and the checkbox element:
<div class="checkbox jobs" v-for="j in jobs" :key="j">
<label>
<input type="checkbox" v-model="filters.jobsChecked.j"
#change="filterJobs(j)"> {{ j }}
</label>
</div>
with filterJobs() firing when I click one of these boxes:
filterJobs(j) {
if (!this.filters.jobs.includes(j)) {
this.filters.jobs.push(j);
this.filters.jobsChecked[j] = true;
} else {
const index = (ele) => ele === j;
const remove = this.filters.jobs.findIndex(index);
this.filters.jobs.splice(remove, 1);
this.filters.jobsChecked[j] = false;
}
console.log("jobs filters: ", this.filters.jobs);
console.log("jobs checked: ", this.filters.jobsChecked);
}
Expected output: The function receives "j" which is read as the string "Baker". The syntax for modifying an Object's property works and checking "Baker" pushes Baker to the filters.jobs array AND uses filters.jobsChecked.j to make filters.jobsChecked.Baker = true
Actual output: The function receives "j" which is read as the string "Baker", pushes "Baker" into the filters.jobs array, but then adds the key/value 'j: true' to filters.jobsChecked.
My confusion comes in here where I am expecting that, since the rest of the function seems to be fully aware the 'j' is not actually the letter j, but instead a passed variable with the value of "Baker", it will know that "filters.jobsChecked.j" = "filters.jobsChecked.Baker" and using object modification syntax, it should change the value to true as I wrote.
I have been reading other posts and websites all night about this and nothing I found made any sense or seemed to englighten me on this situation. As far as I can see, I am writing it exactly as it should be and using [] square notation since it's a variable being passed in.
I also tried writing ['j'] but that also just ADDED the key value "j: false" to the object...
What am I missing here? I have a feeling it's something stupidly obvious...
There is invalid syntax for accessing the string contained in j in the context of an object property.
filters.jobsChecked.j is looking for a property named "j" on the jobsChecked object, but it doesn't exist. Use bracket notation to evaluate j as a variable:
filters.jobsChecked[j]
I am trying to look for texbox values matching an array I have provided a code snippet below:
$('#message').on('keyup', function () {
suggest_array_sample = [
{ array_val: "#{person1}" },
{ array_val: "#{person2}" },
{ array_val: "#{person3}" }
];
found_variable_array = [];
$.each(suggest_array_sample, function (key, value) {
console.log(value);
if ($.inArray(value, textbox_value)) {
console.log('found');
found_variable_array.push(value);
} else {
console.log('not found');
}
})
console.log(found_variable_array);
});
<textarea id="message"></textarea>
The problem is it always return the whole array instead of just the matches the ouput should be when I type #{person1} on the textbox the output should be
[{array_val:"#{person1}"}] //expected output
[{array_val:"#{person1}"},{array_val:"#person2"}]// expected output when two or more matches are found on the textbox
instead of
[{array_val:"#{person1}"},]{array_val:"#{person2}",{array_val:"#{person3}"}] //current output
is this possible using the inArray() or do I need to change the code.
use filter method of Array.
yourArray.filter ( yourArrayModel => yourArrayModel.fieldValue === yourSearchValue )
In your case yourSearchValue can be “{#person1}”
For more information, look for filter method documentation, i hope this is what you want.
$.inArray return a position, if not found return -1 else return >= 0
The $.inArray() method is similar to JavaScript's native .indexOf()
method in that it returns -1 when it doesn't find a match. If the
first element within the array matches value, $.inArray() returns 0
Try this code
$('#message').on('keyup', function () {
textbox_value = $(this).val();
suggest_array_sample = ["#{person1}", "#{person2}", "#{person3}"];
console.log($.inArray(textbox_value, suggest_array_sample));
});
It's not entirely clear what you're trying to achieve. I've written something using $.inArray that tells you the array index of the found value. You need to use .map() on the array to extract the val you want.
EDIT:
From what I understood of your comment, I've now had the value be added to found_value_array each time the value is found.
Or is it that you want an array to be returned because the same value might appear multiple times?
let found_variable_array = [];
$('#message').on('keyup',function(){
suggest_array_sample = [
{array_val:"#{person1}"},
{array_val:"#{person2}"},
{array_val:"#{person3}"}
]
let index = $.inArray($(this).val(), suggest_array_sample.map(o => o.array_val));
if (index >= 0) found_variable_array.push(suggest_array_sample[index]);
console.log(found_variable_array);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="message"></textarea>
After combining ideas presented here this method work for me
match_value = suggest_array.filter(function(result){
if(textbox_value){
return textbox_value.search(result)>-1
}
else{
return false
}
})
console.log(match_value);
So I'm rendering my textarea dynamically using ngFor however I'm not sure how I can pass the ngModel to bind it in my function.
<div *ngFor="let inputSearch of searchBoxCount; let i = index" [ngClass]="{'col-sm-3': swaggerParamLength=='3', 'col-sm-9': swaggerParamLength=='1'}">
<textarea name="{{inputSearch.name}}" id="{{inputSearch.name}}" rows="3" class="search-area-txt" attr.placeholder="Search Product {{inputSearch.name}}"
[(ngModel)]="inputSearch.name"></textarea>
</div>
textarea example:
textarea is render based on the length of the response I get from api call in my case searchBoxCount is basically searchBoxCount.length, so if it length is = 1 then it will only render 1 textarea if its 3 then it will show 3 textareas. The objs have different names (example: id/email/whatever), so ngModel is based on the obj name from the json object.
How do I bind inputSearch.name to my function getQueryString()
getQueryString() {
this.isLoading = true;
let idInputValue = inputSearch.name; //bind it here
return "?id=" + idInputValue
.split("\n") // Search values are separated by newline and put it in array collection.
.filter(function(str) {
return str !== ""
})
.join("&id=");
}
Search func where getQueryString() is called
searchProduct() {
let queryString1 = this.getQueryString();
this._searchService.getProduct(queryString1)
.subscribe(data => {
console.log(data);
});
}
I know how to do it if the ngModel is not coming from the ngFor, is there another way to get the value from the textarea without ngModel? maybe that's the only way or if I can still use ngModel.
Summary of current state
First, let me summarize where your data is. You have a list of one or more objects named searchBoxCount. Each of the elements in the list is an object which has a name property, so you could, for example, call let name = this.searchBoxCount[0].name; to get the name of the first object in the list.
In the HTML template you use ngFor to loop through all of the objects in the searchBoxCount list, and in each iteration you assign the object to a local (to the ngFor) variable named inputSearch. You then bind the input from the textarea created in each loop iteration to the name property for that iteration's inputSearch object.
How to get your data
The key here is that the inputSearch is the same Object as is stored in searchBoxCount at some particular index (index 0 for the first object, etc...). So when the ngModel is tied to inputSearch.name it is also bout to searchBoxCount[n].name. External to the ngFor, you would loop through the searchBoxCount list to get each name you need.
As a consequence
Based on the comments on the original post, it sounds like you can have one or
more names that you need to include in the query string output. That means for your getQueryString() to work, you have to loop through the list (or as in this case, let the list loop for us):
getQueryString() {
this.isLoading = true;
let result : string = "?id=";
this.searchBoxCount.forEach(
(inputSearch:any) => { //Not the same variable, but same objects as in the ngFor
result = result + inputSearch.name + "&id=";
});
result = result.slice(0, result.length - 4); //trim off the last &id=
return result;
}
Edit: Multiple different fields with different names
From the comments on this post, it now is clear each inputSearch has its own key to be used in the query string, that is stored in the name property. You need to preserve that name, which means you can't bind the ngModel to it. Otherwise the user will destroy the name by typing in their own text and there will be no way to get the correct key back. To that end, you need to store bind the ngModel to some other property of the inputSearch object. I am going to assume the object has a value property, so it looks like this:
{
name: "id",
value: "33\n44"
}
That is, each inputSearch has a name, and the value will have one or more values, separated by new line. You would then have to change the HTML template to this:
<div *ngFor="let inputSearch of searchBoxCount; let i = index"
[ngClass]="{'col-sm-3': swaggerParamLength=='3', 'col-sm-9':
swaggerParamLength=='1'}">
<textarea name="{{inputSearch.name}}"
id="{{inputSearch.name}}" rows="3" class="search-area-txt"
attr.placeholder="Search Product {{inputSearch.name}}"
[(ngModel)]="inputSearch.value"></textarea>
</div>
Notice that I changed the ngModel from inputSearch.name to inputSearch?.value (the ? allows for null if there is no value to begin with) inputSearch.value. The getQueryString() method then looks something like this:
getQueryString() {
let result:string = "?";
//for each of the input search terms...
this.searchBoxCount.forEach( (inputSearch:any) => {
// first reparse the input values to individual key value pairs
let inputValues:string = inputSearch.value.split("\n")
.filter(function(str) { return str !== "" })
.join("&" + inputSearch.name + "=");
// then add it to the overall query string for all searches
result = result +
inputSearch.name +
"=" +
inputValues +
"&"
});
// remove trailing '&'
result = result.slice(0, result.length - 1);
return result;
}
Note, using RxJs this is probably easier but I am testing vanilla javascript.
Using this, if the user entered two IDs (33 and 44), a single sku, and two emails, the result would be ?id=33&id=24&sku=abc123&email=name#compa.ny&email=an.other#compa.ny
I have a computed property thats not firing when a checkbox is checked. I just need to switch a property's value from 1 to 0 if its checked.
App.Address = Ember.Object.extend({
shipType: 1,
shipType: function() {
var type = this.get('shipType');
if (type === 1) {
type = 0;
return type;
} else {
type = 1;
return type;
};
}.property('shipCommerical')
})
And in my template:
<label>{{view Ember.Checkbox checkedBinding='shipCommerical'}} Check Me </label>
I have other computed properties located in the same place and in the same way. The only difference is they are text fields and not checkboxes. Does that make a difference?
Well, you've got ship commercial spelled incorrectly, but it appears you have it spelled incorrectly in both places. Additionally you have a recursive loop where your computed property needs itself, I'm going to assume you meant to use shipCommercial instead of shipType inside the computed property.
Template
<label>{{input type='checkbox' checked=shipCommercial}} Check Me </label>
Properties
shipCommercial:true,
shipType: function() {
var shipCommercial = this.get('shipCommercial');
return shipCommercial ? 0 : 1;
}.property('shipCommercial')
Example
http://emberjs.jsbin.com/zimopise/1/edit
I'm having some trouble getting angular to properly filter my results. I'm attempting to use a custom filter that gets arguments from a minimum input and a maximum input.
/index.html
<input ng-model="minHorsepower">
<input ng-model="maxHorsepower">
...
tr(ng-repeat="plane in planes | filter:horsepowerFilter")
/controllers.js
//Horsepower filter
$scope.horsepowerFilter = function(plane) {
var ret = true;
if($scope.minHorsepower && $scope.minHorsepower > plane.horsepower) {
ret = false;
}
if($scope.maxHorsepower && $scope.maxHorsepower < plane.horsepower) {
ret = false;
}
return ret;
};
$scope.planes = [
{
'make' : 'Piper',
'model' : 'Arrow',
'modelNumber' : 'PA-28R-180',
'horsepower' : '180',
'gear' : 'retractable',
},
{
'make' : 'Piper',
'model' : 'Arrow',
'modelNumber' : 'PA-28R-200',
'horsepower' : '200',
'gear' : 'retractable',
}
];
It works INITIALLY when I set $scope.minHorsepower/$scope.maxHorsepower in controllers.js, but only initially, not when I put something else in the <input>s. Furthermore, it prefills the inputs AND filters the results. It just doesn't work properly when I change the value of the inputs.
I've referenced this Stack Overflow thread, but I can't find any material differences in our code... AngularJS multiple filter with custom filter function
Thanks for the help.
To ensure the model values are numbers and not strings, change the type for your inputs to be number.
<input type="number" ng-model="minHorsepower" />
<input type="number" ng-model="maxHorsepower" />
Also, make sure your model values are numbers and not strings.
Alternatively, you can run everything through parseFloat(...) in your filter.
Unfortunately, I can't pinpoint exactly the problem you're having with your code. However, I think I have created a plnkr that (I believe) works as intended.
Apart from parsing the inputs with parseFloat, the logic seems to be the same. Not parsing the inputs to a numeric form shouldn't "break" it, but will possibly make it behave strangely ("9" > "10" for example).
Anyway, hopefully you can pull out the useful pieces and get it working.
Since you only send to the filter a function, it doesn't know to watch for any value changes, and thus to trigger the filter function when it happens.
When you define a filter as {{ filter_expression | filter : filterValue}}, angular watches the filterValue and triggers the filter function when it changes.
To achieve what you need you can define your own filter:
angular.module('myApp')
.filter('range', function(){
return function(items, property, min, max) {
return items.filter(function(item){
return item[property] >= min && item[property] <= max;
});
};
});
and call it like this:
ng-repeat="plane in planes | range : 'horsepower' : minHorsepower : maxHorsepower"