Replacing model in an ArrayController, custom finder, communication between components


#1
Ember      : 1.4.1+pre.af87bd20 
Ember Data : 1.0.0-beta.7.f87cba88 
Handlebars : 1.3.0 
jQuery     : 2.1.0 

I have two components on a template, one is a search wizard which allows you to add search terms to a table, the search terms are then used to build a ‘query’ that returns objects of type (let’s call them) ‘Widgets’.

The second component is a viewer for object of type X which groups them according to certain characteristics.

My route is a traditional ArrayController Route:

MyApp.WidgetsRoute = Ember.Route.extend(Ember.SimpleAuth.AuthenticatedRouteMixin,
  model: ->
    @store.find 'widgets'

setupController: (controller, model) ->
  controller.set 'content', model
  ...
)

The two components work well individually, on the template (widgets.hbs) I have:

<h3>Widgets</h3>
{{search-widgets-by-attribute}}
{{grouped-widgets model=content}}
{{#link-to 'widgets.new'}}New Widget{{/link-to}}
{{outlet}}

The grouped-widgets component correctly displays all the widgets retrieved in the route. The question is how to clear and set the model of the controller so that the search results (retrieved by the search-widgets-by-attribute component) are reflected in the grouped-widget component.

This is what I’ve tried:

  1. Pass the controller model to the search-widgets-by-attribute

{{search-widgets-by-attribute model=content}}

and in the component the doSearch action tries to set the model:

MyApp.SearchWidgetsByAttributeComponent = Ember.Component.extend(
  ...
  actions:
    doSearch: ->
        component = @
        store = MyApp.__container__.lookup('store:main')
        store.searchByTypeAndUrl("widget", "/widgets/search",
          search:
            attribute_names: @.get('searchAttributes')
        ).then (searchResults) ->
          component.set('model', searchResults)
)

The searchByTypeAndUrl returns an Array of Widgets. Setting the model above results in:

Results in:

Uncaught TypeError: Cannot read property 'firstChild' of null
firstNodeFor 
prependFunc 
DOMManager.prepend 
insertViewCollection
Ember.merge.ensureChildrenAreInDOM 
Ember.ContainerView.Ember.View.extend._ensureChildrenAreInDOM 
DeferredActionQueues.flush 
Backburner.end 
(anonymous function)

I’ve also tried wrapping the plain JS array of Widgets using Em.Array and Em.ArrayProxy and Em.MutableArray to no avail.

  1. Passing the controller to the the search-widgets-by-attribute

{{search-widgets-by-attribute widgetsController=controller}}

and in the component the doSearch action tries to set the model:

MyApp.SearchWidgetsByAttributeComponent = Ember.Component.extend(
  ...
  actions:
    doSearch: ->
        widgetsController = @.get('widgetsController')
        store = MyApp.__container__.lookup('store:main')
        store.searchByTypeAndUrl("widget", "/widgets/search",
          search:
            attribute_names: @.get('searchAttributes')
        ).then (searchResults) ->
          widgetsController.set('model', searchResults)
)

Results in:

Uncaught TypeError: Cannot read property 'firstChild' of null
firstNodeFor 
prependFunc 
DOMManager.prepend 
insertViewCollection
Ember.merge.ensureChildrenAreInDOM 
Ember.ContainerView.Ember.View.extend._ensureChildrenAreInDOM 
DeferredActionQueues.flush 
Backburner.end 
(anonymous function)
  1. Setting the model using the find method

This just works! But it is not what I wanted :frowning: The hint I got from this is that I seem to need a DS.RecordArray!

 MyApp.SearchWidgetsByAttributeComponent = Ember.Component.extend(
  ...
  actions:
    doSearch: ->
        store = MyApp.__container__.lookup('store:main')
        component = @
        store.find('specification').then (specifications) ->
          component.set('model', specifications)

Next Steps…

The code for searchByTypeAndUrl looks like:

MyApp.Store = DS.Store.extend(
  revision: 11
  searchByTypeAndUrl: (type, url, params) ->
    self = this
    promise = Ember.Deferred.create()

    $.getJSON url, params, (payload) ->
      serializer = self.serializerFor(type)
      payload = serializer.extractArray(self, self.modelFor(type), payload)
      objects = self.pushMany(type, payload)
      promise.resolve objects

    promise
)

I’ve tried change setting the model to empty array in model hook in the route but I get first child of null even when doing #3 above.

My last attempt will be to make searchByTypeAndUrl return a RecordArray. Any suggestions will be welcomed.

Cheers, Brian