I have an input field that is supposed to contain numbers.
It is bound to an object property.
I want input entered as 4,5 to automatically get converted to 4.5 in both model and view.
HTML:
<input data-ng-model="productContent(product.Id).Org" value="{{productContent(product.Id).Org | replaceComma}}" />
Control:
$scope.productContent = function (prodId) {
var content = $.grep($scope.productsContent, function (el) { return el.ProdId === prodId });
return content[0];}
Filter:
app.filter('replaceComma', function () {
return function (val) {
return (typeof val) == "string" ? val.toString().trim().replace(",", ".") : val
};
});
Result:
When I enter a number, at first the model (productContent) retrieves the correct object. Then the filter code is called and returns a correctly converted string. I would expect both the model and view to be updated to the filtered value, but both are updated with the unfiltered value. What am I doing wrong?
I have faced the same problem in the past but instead of creating my own filter, I took a different path and found something ready to use instead.
angular-input-masks by assisrafael one of my favourite angular extensions for this purpose:
https://github.com/assisrafael/angular-input-masks
Examples:
http://assisrafael.github.io/angular-input-masks/
Since the author has written the documentation, I don't want to get extensive on it and be outdated in the future. As a quick reference, look for ui-number-mask.
Maybe this is not a direct answer to your question, since it's not replacing commas with periods, but making you type the decimals instead.
On a side note, you can suppress the thousands separators with ui-hide-group-sep
I hope that's helpful, otherwise leave a comment and I'll be happy to continue to assist you!
-Helvio
Related
I'm adding tag by selecting from list (which is populated using $http request). The tag is added but the text which I have typed that remains there with ng-invalid-tag class.
ScreenShots
1) Initially,
2) Typing 3 letters to get HTTP Call.
3) Now after selection of first Skill "Angular Js'.
4) It shows that .input.invalid-tag is enabled. And which doesn't clear the placeholder.
My Input Tag is as below.
<tags-input ng-model="employerMyCandidatesCtrl.skillList" placeholder="Skills..."
replace-spaces-with-dashes="false"
add-from-autocomplete-only="true"
display-property="skillName"
on-tag-added="employerMyCandidatesCtrl.addTagToSkillData($tag)"
on-tag-removed="employerMyCandidatesCtrl.removeTagFromSkillData($tag)">
<auto-complete
source="employerMyCandidatesCtrl.loadSkillData($query)"
displayProperty="skillName" debounce-delay="500"
min-length="3">
</auto-complete>
</tags-input>
Controller Code is as below.
vm.skillList = [];
vm.loadSkillData = function(query) {
return EmployerServices.getAllSkillsPromise(query); // $http call.
};
vm.addTagToSkillData = function(tag) {
if (_.findIndex(vm.skillList, tag) < 0) {
vm.skillList.push(tag);
}
};
vm.removeTagFromSkillData = function(tag) {
var ind = _.findIndex(vm.skillList, tag) > -1 ? vm.skillList.splice(ind, 1) : '';
};
Is any configuration mistake I'm doing?
There are 4 attributes for onTagAdding, onTagAdded, onTagRemoving, onTagRemoved so the basic difference between the attributes ending with adding compared to those ending with added is
Adding suffixed tags are expecting a boolean which when true will be added
or removed based on the tag used.
But onTagAdded/Removed already adds the tag, before the function is called hence we can do some additional logic or else strip the ng-model of the added value or add back the removed value(not very easy).
Check the below JSFiddle to see the four attributes in action here
I have made a custom service to supply the data, so the final answer to your question will be to use the appropriate attribute (onTagAdding, onTagAdded, onTagRemoving, onTagRemoved) based on your usecase. From the above code, I think we need not write onTagAdded, onTagRemoved since its done automatically.
https://material.angularjs.org/latest/#/demo/material.components.autocomplete
Please can someone tell me how to make autocomplete (Angular material) to search string not only at the beginning of words, but anywhere within the words.
For example the word Alabama:
Works when you type "Ala", but does not work when you type "bama".
How do I make it to work when I type "bama"?
I know I can use a third party directive such as Angucomplete Alt:
http://ghiden.github.io/angucomplete-alt/
but I think Angular material should have this option?
This is a function from the original md-autocomplete:
function createFilterFor(query) {
var lowercaseQuery = angular.lowercase(query);
return function filterFn(state) {
return (state.value.indexOf(lowercaseQuery) === 0);
};
}
Please try changing the condition a little bit, like this:
return (state.value.indexOf(lowercaseQuery) >= 0);
and it should work the way you want.
The demo only matches characters at the beginning of the result due to specifying the caret flag, ie: md-highlight-flags="^i"
To allow autocomplete to find any matching characters you should use the global flag, ie: md-highlight-flags="gi"
You will also need to change the state.value.indexOf(lowercaseQuery) === 0 line in the filterFn function to state.value.indexOf(lowercaseQuery) !== -1
Check this codepen for a working example:
http://codepen.io/DevVersion/pen/KrOYoG
So I have this:
var competitionModel = new Competition.CompetitionModel();
competitionModel.contest_id = this.contest_id;
this.insertView('.comp', new Competition.View({model: competitionModel}));
competitionModel.fetch();
So far so good, the Model and its (selected) values are getting display in the <div class="comp">.
Now I want to get a specific value from the same Model, in this case profile_image and it has to be the MAX value from the model. I read something about .max()-method but I dont know how to use it
I have this structure:
<div class="image"></div>
<div class="comp"></div>
1) is it possible? 2) can I use the same methods? like this.insertView('.image', blablab)
So, could anyone help me out?
Ok, judging by your comment the property is an array of things.
You cannot use the backbone max (which only applies to collections) but you can use the underscore max (they are the same thing, in the end, the former is a wrapper for the latter but let's not go into the details). You can see the collection .max() in action here.
You should be able to do something like this:
var max = _.max(competitionModel.get("property"));
Eventually you can pass a function to transform values:
var max = _.max(competitionModel.get("property"), function (element) {
// element is a single item in the list, return a number here.
});
Alternatively you can also use the underscore wrapper like this:
var max = _(competitionModel.get("property")).max(function (e) { ... });
More on max() can be found in the Underscore Docs.
I'm trying display some data loaded from a datastore and it's not reflecting changes on the UI. I created an example to show a general idea of what I'm trying to achieve.
http://plnkr.co/edit/MBHo88
Here is the link to angularjs example where they show when on click then dropdowns are clear out. If you replace the expression with one of the colors of the list dropdowns are well selected. Does this type of selection only work on user events?
http://docs.angularjs.org/api/ng.directive:select
Help is appreciated!!!
Actually the problem is that ngSelect compares objects using simple comparition operator ('=='), so two objects with same fields and values are considered as different objects.
So you better use strings and numbers as values ('select' parameter in expression of ngSelect directive).
Here is kind of solution for your plunker.
Aslo there are some discussion about this topic on GitHub:
https://github.com/angular/angular.js/issues/1302
https://github.com/angular/angular.js/issues/1032
Also as I headred there is some work in progress about adding custom comparor/hashing for ngSelect to be able to use ngSelect more easier on objects.
One mistake in the initialization of your controller. You have to refer to the objects in your palette, since these are watched on the view:
$scope.selectedColors.push({col: $scope.palette[2]});
$scope.selectedColors.push({col: $scope.palette[1]});
Same with your result:
$scope.result = { color: $scope.obj.codes[2] };
Then you need to watch the result. In the below example, select 1 receives the value from the initiating select, the second receives the value below in the palette. I don't know if that's what you wanted, but you can easily change it:
$scope.$watch('result', function(value) {
if(value) {
var index = value.color.code -1;
$scope.selectedColors[0] = {col: $scope.palette[index] };
$scope.selectedColors[1] = {col: $scope.palette[Math.max(index-1, 0)] };
}
}, true);
See plunkr.
Ok, I think I figured this out but thanks to #ValentynShybanov and #asgoth.
According to angularjs example ngModel is initialized with one of the objects from the array utilized in the dropdown population. So having an array as:
$scope.locations = [{ state: 'FL', city: 'Tampa'}, {state: 'FL', city: 'Sarasota'} ....];
And the dropdown is defined as:
<select ng-options="l.state group by l.city for l in locations" ng-model="city" required></select>
Then $scope.city is initialized as:
$scope.city = $scope.locations[0];
So far so good, right?!!!.. But I have multiple locations therefore multiple dropdowns. Also users can add/remove more. Like creating a table dynamically. And also, I needed to load data from the datastore.
Although I was building and assigning a similar value (e.g: Values from data store --> State = FL, City = Tampa; Therefore --> { state : 'FL', city : 'Tampa' }), angularjs wasn't able to match the value. I tried diff ways, like just assigning { city : 'Tampa' } or 'Tampa' or and or and or...
So what I did.. and I know is sort of nasty but works so far.. is to write a lookup function to return the value from $scope.locations. Thus I have:
$scope.lookupLocation = function(state, city){
for(var k = 0; k < $scope.locations.length; k++){
if($scope.locations[k].state == state && $scope.locations[k].city == city)
return $scope.locations[k];
}
return $scope.locations[0]; //-- default value if none matched
}
so, when I load the data from the datastore (data in json format) I call the lookupLocation function like:
$scope.city = $scope.lookupLocation(results[indexFromSomeLoop].location.state, results[indexFromSomeLoop].location.city);
And that preselects my values when loading data. This is what worked for me.
Thanks
My form in the html DOM is a checkbox to click (there can be more than one). The problem occurs in the description string when ever I use an apostrophe, since my list object is single-quote deliniated. This is one of the checkboxes in the form:
<input type="checkbox" id="cbx" name="cbx" value="{'getPic': 'url', 'picsrc': 'http://lh3.ggpht.com/_ZB3cttqooN0/SVmJPfusGWI/AAAAAAAADvA/GuIRgh6eMOI/Grand%20Canyon%201213_121508214.JPG', 'pos': None, 'description': 'Here's what it REALLY looks like at 5:30am! Bring your headlight!'}">
The javascript that reads the values of the checked checkboxes and pushes them into an array (list):
var pylist = [];
for (i=0; i<document.picList.cbx.length; i++) {
if (document.picList.cbx[i].checked) {
pylist.push( document.picList.cbx[i].value );
}
}
var getstr = JSON.stringify(pylist);
The problem is always that getstr at this point has chopped off everthing after the single quote in the description property.
I've tried different ways of escaping it to little avail.
The problem is that the value of the checkbox already is a JSON string. One solution would be to call JSON.parse() on the value:
var pylist = [];
for (i=0; i<document.picList.cbx.length; i++) {
if (document.picList.cbx[i].checked) {
pylist.push( JSON.parse( document.picList.cbx[i].value) );
}
}
var getstr = JSON.stringify(pylist);
I've run into the same issue - we stick json in a hidden field so we don't have to query the server on every page. We replace apostrophes with a "code" before putting into the html - we added a javascript function that replaces the code with an apostrophe.
Really hacky, but it works really well. Of course, we have one place in the code that gets json from the server and one place where javascript needs to parse it - if you find you're repeating the methods throughout your code, your mileage will vary.