John Altar
John Altar

Reputation: 141

Observer not getting fired in Ember

I have a very weird issue, I have two observers in my App but only one of them fires properly. I am not sure why this is happening.

Here's the controller in question:

App.TwodController = Ember.ArrayController.extend({
    //filteredContent : null,
    init : function() {
        this.set('filteredContent', []);
    },
    //sortProperties : ['firstname'],

    //sortAscending : true,
    selectedExperience : null,
    filterExperience : function() {
        var exp = this.get('selectedExperience.exp');
        var filtered = this.get('arrangedContent').filterProperty('experience', exp);
        this.set("filteredContent", filtered);
    }.observes('selectedExperience'),
    experience : [{
        exp : "1"
    }, {
        exp : "2"
    }, {
        exp : "3"
    }, {
        exp : "4"
    }, {
        exp : "5"
    }],
    selectedDesignation : null,
    filterDesignation : function() {
        var designation = this.get('selectedDesignation.designation');
        var filtered = this.get('arrangedContent').filterProperty('designation', designation);
        this.set("filteredContent", filtered);
    }.observes('selectedDesignation'),
    designations : [{
        designation : "Design",
        id : 1
    }, {
        designation : "Writer",
        id : 2
    }, {
        designation : "Script",
        id : 3
    }, {
        designation : "Storyboard",
        id : 4
    }, {
        designation : "Workbook",
        id : 5
    }],
    actions : {
        filterExperience : function() {
            var experience = this.get('selectedExperience.exp');
            var filtered = this.get('content').filterProperty('experience', experience);
            this.set("filteredContent", filtered);
        },
        refresh : function() {
            var refresh = this.get('content');
            this.set("filteredContent", refresh);
        }
    },
    filteredContent : function() {
        var searchText = this.get('searchText'), regex = new RegExp(searchText, 'i');

        return this.get('model').filter(function(item) {
            var fullname = item.firstname + item.lastname;
            return regex.test(fullname);
        });
    }.property('searchText', 'model')

});

As you can see, I have filterDesignation & filterExperience. But only filterExperience works as expected not the filterDesignation.

Moreover here is the HTML Template for that Controller:

<script type="text/x-handlebars" id="twod">
    <div class="row">
        <div class="span4">
            <img src="/img/2DPipeline.jpg"/>
        </div>

        <div class="span4">
            <h4>2D Roles</h4>

            {{view Ember.Select
            contentBinding="designations"
            optionValuePath="content.id"
            optionLabelPath="content.designation"
            selectionBinding="selectedDesignation"
            prompt="Please Select a Role"}}
            {{view Ember.Select
            contentBinding="experience"
            optionValuePath="content.exp"
            optionLabelPath="content.exp"
            selectionBinding="selectedExperience"
            prompt="Please Select Experience"}}


            <br/>
            <!-- <button {{action 'filter'}}>Filter By Designation</button>
            <button {{action 'filterExperience'}}>Filter By Experience</button>
            <button {{action 'refresh'}}>Refresh</button> -->            </div>

        <div class="span3">
            <h4>People with Roles</h4>
            {{input type="text" value=searchText placeholder="Search"}}
            <div class="row">

                <div class="span2">
                    <ul>

                        {{#each item in filteredContent}}
                        <li>{{#link-to 'twoduser' item}}{{item.firstname}}&nbsp;{{item.lastname}} {{/link-to}}</li>

                        {{/each}}

                    </ul>
                </div>
                <div class="row">
                    <div class="span3">
                        {{outlet}}
                    </div>
                </div>
            </div>
        </div>
    </div>
</script>

Here's the full JSBin as well.

What might be the issue?

Edit: The Search box in "Twod" Template doesn't work. Any ideas why?

Upvotes: 0

Views: 873

Answers (1)

Kingpin2k
Kingpin2k

Reputation: 47367

The observer is working. Your JSON appears to contain additional whitespace. The designation value for each record has a space on the front and back of the value.

 designation: " Design "

the filter is looking for

 designation: "Design"

trimming your designation on the server should fix this up.

Additional issue(s):

Is filteredContent an array, or a computed property? You are blasting away your computed property on init and replacing the filteredContent computed property with an empty array

 init : function() {
      this.set('filteredContent', []);
 },

or this?

 filteredContent : function() {
    var searchText = this.get('searchText'), regex = new RegExp(searchText, 'i');

    return this.get('model').filter(function(item) {
        var fullname = item.firstname + item.lastname;
        return regex.test(fullname);
    });
 }.property('searchText', 'model')

Additionally you are filtering in multiple places, so one filter will totally blast away another filter. So I ripped out the observes for each one of those drop downs, and removed the init destroying the filteredContent array.

 filteredContent : function() {
  var designation = this.get('selectedDesignation.designation'),
      hasDesignation = !Ember.isEmpty(designation),
      experience = this.get('selectedExperience.exp'),
      hasExperience = !Ember.isEmpty(experience),
      searchText = this.get('searchText'),
      hasSearch = !Ember.isEmpty(searchText),
      regex = hasSearch ? new RegExp(searchText, 'i') : undefined;


    return this.get('model').filter(function(item) {
      var fullname = Em.get(item,'firstname') + Em.get(item,'lastname');

      return (!hasDesignation || Em.get(item, 'designation') === designation) &&
             (!hasExperience || Em.get(item, 'experience') === experience) &&
             (!hasSearch || regex.test(fullname));
    });
}.property('searchText', 'model', 'selectedExperience.exp', 'selectedDesignation.designation')

http://jsbin.com/aHiVIwU/27/edit

BTW

If you don't want it to show anything until they've filtered at least one thing, instead of setting filtered content to an empty array in the init, you would do that in the computed property, filteredContent, like so (before the filter):

if(!(hasDesignation|| hasExperience || hasSearch)) return [];

Ember isEmpty

  Verifies that a value is `null` or an empty string, empty array,
  or empty function.

  Constrains the rules on `Ember.isNone` by returning false for empty
  string and empty arrays.

    ```javascript
    Ember.isEmpty();                // true
    Ember.isEmpty(null);            // true
    Ember.isEmpty(undefined);       // true
    Ember.isEmpty('');              // true
    Ember.isEmpty([]);              // true
    Ember.isEmpty('Adam Hawkins');  // false
    Ember.isEmpty([0,1,2]);         // false
    ```

Upvotes: 1

Related Questions