2

I am trying to find a model within a collection with an attribute equal to html select option value.

<div id="hospital-details">
    <select name="hospitalnames">
       <option><%- model.get('name') %></option>
    </select>
</div>

whenever hospital name is changed, jquery change callback is triggered to find locationModel with selected option value as attribute value as shown below,

$('select[name="hospitalnames"]').change(function() {
   var name =  $(this).val();
   locationListCollection.each(function(locationModel) {
     if ($.trim(locationModel.get('name')) == $.trim(name)) {
        that.locationModel = locationModel;
        return false; // control is returned to underscore.min.js
     }
   });
});
console.log(that.locationModel); // this is not being displayed at all

After the locationModel with an attribute is found, I am unable to come out the loop. Any help ? At this moment I have looked into this but without success.

Community
  • 1
  • 1
geekgugi
  • 389
  • 1
  • 6
  • 22

4 Answers4

9

You're using the wrong method if you're searching for the first match. Collections have lots of Underscore methods mixed in, in particular they have find mixed in:

find _.find(list, iterator, [context])

Looks through each value in the list, returning the first one that passes a truth test (iterator), or undefined if no value passes the test.

Something like this:

var name = $.trim($(this).val());
that.locationModel = locationListCollection.find(function(locationModel) {
  return $.trim(locationModel.get('name')) == name;
});

and if the names in your model are pre-trimmed and nice and clean, then you could use findWhere:

findWhere collection.findWhere(attributes)

Just like where, but directly returns only the first model in the collection that matches the passed attributes.

like this:

var name = $.trim($(this).val());
that.locationModel = locationListCollection.findWhere({ name: name });

BTW, this:

console.log(locationModel);

won't give you anything because locationModel and that.locationModel are different things.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
3

You can always go oldschool.

$('select[name="hospitalnames"]').change(function() {
   var name =  $(this).val();
   for (var i = 0; i < locationListCollection.length; ++i) {
     var locationModel = locationListCollection.models[i];
     if ($.trim(locationModel.get('name')) == $.trim(name)) {
        that.locationModel = locationModel;
        break;
     }
   }
});
dthree
  • 19,847
  • 14
  • 77
  • 106
1

Try this,

var name =  $(this).val();
var flag=true;
locationListCollection.each(function(locationModel) {
  if (flag && $.trim(locationModel.get('name')) == $.trim(name)) {
     that.locationModel = locationModel;
     flag=false;
      //return false;// to break the $.each loop
  }
});
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
0

The short is no.

If you take a look at underscore's source you'll see that they use a breaker object to quickly stop a .each() but that is only available internally.

I would not recommend this but you could always modify the source to expose this breaker object (see baseline setup in the annotated source http://underscorejs.org/docs/underscore.html). Then you would just return this object instead of returning false. But you would probably need to remove the native forEach call to keep the behaviour consistent. So it's not worth it!

_.each(function(arr) {
    if(condition) {
       return _.breaker; // Assuming you changed the source.
    }
});

Since you are searching for a single item instead of .each() use:

 var locationModel = _.find(arr, function(item) {
    return $.trim(locationModel.get('name')) == $.trim(name);
 ));
Craig MacGregor
  • 4,589
  • 1
  • 21
  • 13
  • I am searching for locationModel within LocationListCollection , in that case arr will be locationListCollection ? – geekgugi Oct 09 '13 at 05:31