AngularJs search and ignoring diacritics - angularjs

My idea is to have a list of words in which there are lots of diacritics or accents. And for example instead of writing Róse to have Róse I'd like to write Rose and have Róse in results.
First of all I googled for it, here in StackOverflow the problem was partially solved.
But what if I have array like this, check jsFiddle:
$scope.names = [{name: 'Jamón', surname: 'Géroux'},
{name: 'Andrés', surname: 'Guérin'},
{name: 'Cristián', surname: 'Róse'},
{name: 'Fernán', surname:'Raúlien'}];
};
Then the solution doesn't work: jsFiddle.
And what if I had, for example, custom filter for highlight:
<td ng-bind-html="name.name | highlight:search.$"></td>
I've fount out, that all examples here https://builtwith.angularjs.org have the same problem with diacritics/accents. And only one website there http://illicoweb.videotron.com uses "simple technics" with JavaScript function and str.replace.
Any ideas on really simple and fast solution? Without storing two tables with diacritics/accents and without it.
Thanks in advance!

I've updated this JSFiddle with my modifications to your filter. I've simply modified the filter to search the full name rather than just the first name as demonstrated:
$scope.ignoreAccents = function(item) {
if (!$scope.search)
return true;
var fullName = item.name + ' ' + item.surname;
var text = removeAccents(fullName.toLowerCase());
var search = removeAccents($scope.search.toLowerCase());
return text.indexOf(search) > -1;
};
This approach should hopefully negate any need for two separate tables.

Related

Put Array in a particular Form in Typescript/Angular

I´m new to stackoverflow and not an english native speaker, so apologies for any mistakes.
We have an Angular/C# project in a course of study and I need an Angular mat-select which works with an ID (number) but displays a String instead.
In my typescript class I already have an Array<number> fruitIDs . Now I want to take every element of the array and apply a function fruitName(fruitID) on it (fruitName(fruitID) returns a string).
My problem is that I need to put the elements of the array and their corresponding function values in a form like:
fruits =
[{value: idOfFirstFruit, viewValue: fruitName(idOfFirstFruit)},
{value: idOfSecondFruit, viewValue: fruitName(idOfSecondFruit)},....]
If I have an object in this form my mat-select can access and save value but display `fruitName(value)' instead.
I hope anyone can help. Thanks in advance!
Ok, if anybody is interested, I found the solution:
var fruitNrs:Array<number> = this.fruits.map(item => {return item.fruitNr});
var objArray: Array<{value:number,viewValue:string}> = [];
for (let fruitNr of fruitNrs){
objArray.push({value:fruitNr,viewValue:this.fruitname(fruitNr)});
}

AngularJS how to have multiple $filter in a controller?

The leftValue array contains JSON information such as { name: 'John', gender: 'male' }
I am trying to filter information by both name and gender in a search bar. For now, the filter only filtered by name. How can I filter by both name and gender?
scope.leftValue = $filter('filter')( leftValue, {
'name': text
})
What I have tried
scope.leftValue = $filter('filter')( leftValue, {
'name': text,
'gender': text,
})
I think your getting a little mixed up. You can specify an object map like your second example. This is what the docs state about it when you do.
Object: A pattern object can be used to filter specific properties on
objects contained by array. For example {name:"M", phone:"1"}
predicate will return an array of items which have property name
containing "M" and property phone containing "1". A special property
name $ can be used (as in {$:"text"}) to accept a match against any
property of the object or its nested object properties. That's
equivalent to the simple substring match with a string as described
above. The predicate can be negated by prefixing the string with !.
For example {name: "!M"} predicate will return an array of items which
have property name not containing "M".
The important thing to take away here is the second sentence and the and. Meaning in order for a match the string, in your case text, has to match ALL properties specified in your map.
Searching for just male wont match if the name is only John for example. But searching for ma would return the following record:
{
name: 'mark',
gender: 'male'
}
Just for FYI you can also search by object map through the view but it has the same limitations.
That being said it is possible to use the $ wildcard giving it a comma separated list of properties. This will do an or match over any of the properties.
{
$: 'name,gender'
}
The catch here is all properties will have the same value checked against them.
Here's a fiddle showing them in action.
The other answers sum up quite well the alternatives, just felt they were lacking in explaining what was happening and the reasons behind it.
You can use chain of filters.
var result1 = $filter('filter')( leftValue, {'name': text })
var result2 = $filter('filter')( result1 , {'gender': text })
i appreciate you said in the controller, but just to give you options you can have it all done in your HTML.
{{yourJSONLinkedToScope | filter: name | filter: gender}}
where name and gender are ng-models from the input boxes.
I think better we do it in html.
<tr ng-repeat="player in players | filter:{id: player_id, name:player_name} | filter:ageFilter">
$scope.ageFilter = function (player) {
return (player.age > $scope.min_age && player.age < $scope.max_age);
}
You can check the way they do in this link:
AngularJS multiple filter with custom filter function

AngularJS limitTo using HTML tags

I have some bindings in AngularJS and I want to limit the length of characters displayed. It's a quite simple question when you have just a simple text content.
However, I have text that contains HTML tags:
$scope.text = "<span><h1>Example</h1><p>Special Text</p></span>"
and also
$scope.maxNumberOfChar = 10;
When I use the following line it counts the number of chars taking into account HTML tags.
Which could be the best solution to solve this problem and count only the number of chars, discarding HTML tags?
Thanks in advance
I've created a solution, using a simple filter and regex operations.
var appFilters = angular.module('myApp.filters', [])
.filter('limitHtml', function() {
return function(text, limit) {
var changedString = String(text).replace(/<[^>]+>/gm, '');
var length = changedString.length;
return changedString.length > limit ? changedString.substr(0, limit - 1) : changedString;
}
})
and the correspondent usage, similar to limitTo filter
<span ng-bind-html="text | limitHtml: maxNumberOfChar"></span>
Note that, in this case I am also using an html-binding, specific of my solution.
I created a filter, the logic is not so good, but it works
<span ng-bind-html="text | limitHtml:maxNumberOfChar"></span>
jsfiddle.net/4x6z283a/1/
To count only the number of non HTML chars, use something similar to the answer to this question:
angularjs to output plain text instead of html
For example:
var text = "<span><h1>Example</h1><p>Special Text</p></span>";
var length = String(text).replace(/<[^>]+>/gm, '').length;
alert(length);
I've included a further example here: http://jsfiddle.net/n3qjm2u5/
Why not displaying it based on a filter length?
Just add a limitTo filter
{{ text| limitTo:maxNumberOfChar }}

How to define hidden properties on Angular $scope

Consider:
$scope.taylor = {
firstName: 'taylor',
lastName: 'mcintyre',
order: 22
}
Using $resource, I might want to save this:
people.save($scope.taylor);
However, I do not want the property "order" to be sent along with the request.
Angular ignores properties prefixed with '$$' for it's own internal use, but it doesn't feel right prefixing my own hidden properties in this way, e.g.
$scope.taylor = {
firstName: 'taylor',
lastName: 'mcintyre',
$$order: 22
}
Deleting unwanted properties is the common-sense solution, but does Angular have a better solution for this?
I know you are looking for an "Angular way" to exclude keys, but angular.copy() doesn't seem to support this. The angular.toJson() documentation states: Properties with leading $ characters will be stripped since angular uses this notation internally. This sounds like using $ should be reserved for angular and not used by us in our objects.
In light of the situation I created a simple CodePen example showing how easily this can be done using a library like UnderscoreJS.
I'm sure there are more elegant ways to do this, but my example does accomplish what I understood to be your primary goal.
I included the UnderscoreJS library in my file and added the following code:
var person = {
firstName: 'John',
lastName: 'Smith',
order: 22,
excludeKeys: [
'order',
'excludeKeys'
]
};
var personCopy = _.omit(person, person.excludeKeys);
console.log('person: ', person);
console.log('person copy: ', personCopy);
I hope this is useful.

Angularjs autoselect dropdowns from model

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

Resources