Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

feat(select): New select attribute directive ng:hasher #1663

Closed
wants to merge 2 commits into from
Closed

feat(select): New select attribute directive ng:hasher #1663

wants to merge 2 commits into from

Conversation

quazzie
Copy link
Contributor

@quazzie quazzie commented Dec 6, 2012

Add new attribute directive for specifying a hashing function for objects.
If ng:model is bound to an object and ng:options is "obj for obj in objs"
a reference equality is used for selection.
With ng:hasher you can bind a function that takes one argument and returns
a hash. Then the hash is used for comparision instead.

Ex.
<select ng-model="selection" ng-options="obj for obj in objs" ng-hasher="hash_func"> /select>

scope: {
  selection: { id: 12, ... },
  objs: [{ id: 12, ... }, { id: 13, ... }],
  hash_func: function(o) {
    return o ? o.id : undefined;
  }
}

Will match model to the first obj in the objs array.

Add new attribute directive for specifying a hashing function for objects.
If ng:model is bound to an object and ng:options is "obj for obj in objs"
a reference equality is used for selection.
With ng:hasher you can bind a function that takes one argument and returns
a hash. Then the hash is used for comparision instead.

Ex.
<select
    ng-model="selection"
    ng-options="obj for obj in objs"
    ng-hasher="hash_func">
</select>

scope: {
  selection: { id: 12, ... }
  objs: [{ id: 12, ... }, { id: 13, ... }
  hash_func: function(o) {
    return o ? o.id : undefined;
  }
}

Will match model to the first obj in the objs array.
@gonzaloruizdevilla
Copy link
Contributor

Yesterday I needed this functionality, and this would make my code much cleaner and simple 👍
@quazzie You should check code indenting between lines 433 and 443

@mhevery
Copy link
Contributor

mhevery commented Jan 17, 2013

This change can be achieved by:

scope.hash_func = function() {};

ng-model="selection"
ng-options="hash_func(obj) for obj in objs">

So the new behavior just introduces a new way to do the same thing. For this reason we will not merge it in. If you feel otherwise feel free to reopen it and provide counter argument.

@mhevery mhevery closed this Jan 17, 2013
@quazzie
Copy link
Contributor Author

quazzie commented Jan 17, 2013

@mhevery : no it is not the same. It will not run the hasher function on the selection/ng-model object, it will not select the object with id 12.

I don't know how to reopen this, i'm a noob git user.

@ProLoser
Copy link
Contributor

What is wrong with object.id as object.label?

@quazzie
Copy link
Contributor Author

quazzie commented Jan 17, 2013

Maybe a better example:

$scope.person = { id:1, name:'Thomas', favorite_movie: { id:2, name: 'Startrek' } };
$scope.movies = [{ id: 1, name: 'Starwars' }, { id: 2, name: 'Startrek' }, { id: 3, name: 'Alien' }];

Without the hashing function i have to:

<select ng-model="movieid" ng-options="movie.id as movie.name for movie in movies"></select>
$scope.movieid = $scope.person.favorite_movie.id;
$scope.$watch('movieid', function() {
  for(var i = 0; i < $scope.movies.length; i++)
    if ($scope.movies[i].id == $scope.movieid)
       $scope.person.favorite_movie = $scope.movies[i];
});

With the hashing function i could just write :

<select ng-model="person.favorite_movie" ng-options="movie as movie.name for movie in movies" ng-hasher="moviehasher"></select>
$scope.moviehasher = function(movie) { return movie ? movie.id : undefined; }

@ProLoser
Copy link
Contributor

What about ng-options="index as movie.name for (index, movie) in movies" and simply retrieve the row you need when necessary (rather than setting up a watch).

I may not be clear on what you wanted but if I understand correctly, I only foresee a plethora of problems with this design:

  • You must ALWAYS set the value to an ID
  • Changing a property of the object may be considered a re-selection?
  • You are setting the model to an ID and it immediately changes to a model inexplicably

It feels like it would create an unreliable and inconsistent behavior.

Dean Sofer
DeanSofer.com
714.900.2254

On Thursday, January 17, 2013 at 1:29 PM, quazzie wrote:

Maybe a better example:
$scope.person = { id:1, name:'Thomas', favorite_movie: { id:2, name: 'Startrek' } }; $scope.movies = [{ id: 1, name: 'Starwars' }, { id: 2, name: 'Startrek' }, { id: 3, name: 'Alien' }];

Without the hashing function i have to:

$scope.movieid = $scope.person.favorite_movie.id; $scope.$watch('movieid', function() { for(var i = 0; i < $scope.movies.length; i++) if ($scope.movies[i].id == $scope.movieid) $scope.person.favorite_movie = $scope.movies[i]; });

With the hashing function i could just write :

$scope.moviehasher = function(movie) { return movie ? movie.id : undefined; }


Reply to this email directly or view it on GitHub (#1663 (comment)).

@petebacondarwin
Copy link
Contributor

How about just changing select to use a deep compare rather than object equality? This would solve many problems that people have with selecting an object rather than an object's id. In the case of the example above:

$scope.person = { id:1, name:'Thomas', favorite_movie: { id:2, name: 'Startrek' } };
$scope.movies = [{ id: 1, name: 'Starwars' }, { id: 2, name: 'Startrek' }, { id: 3, name: 'Alien' }];

This would just work:

<select ng-model="person.favorite_movie" ng-options="movie as movie.name for movie in movies" ></select>

As long as the properties on the person.favorite_movie matched the properties on an object in the movies array.

@quazzie
Copy link
Contributor Author

quazzie commented Jan 17, 2013

Yeah what @petebacondarwin said is what i wanted, but i thought i'd be a bit more clever to allow for more configuration.
With the hasher function i can control what gets compared.

@quazzie
Copy link
Contributor Author

quazzie commented Jan 17, 2013

@ProLoser

  • the hashing function can return anything comparable.
  • changing a property that is included in the hashing should re-select.
  • i don't want to set model to an id, i want to set it to a model/object.

The hashing function should be used with objects. If options is value-types hashing would be unnecessary.

@wagnerfrancisco
Copy link

Im having the same problem. This functionality would be very interesting.

@quazzie
Copy link
Contributor Author

quazzie commented Feb 25, 2013

I wrote another patch that does the same thing but in a diffrent way : #2040

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants