mardi 22 novembre 2016

Ember: Paginating sorted/searched hasMany relationship on single-page application

I am working on a single-page application wherein I have to page a hasMany relationship based on sort and search criteria. The back-end is straightforward but the front-end is giving me troubles. I suspect the problem is architectural and wondered if anyone had any ideas.

Here’s the scenario: You bring up the application and it queries for a list of regions. You select a region, and then query for its hasMany locations. We didn’t used to paginate locations so this was straightforward and you could get them with sideloading. Now we have a requirement to support thousands of locations, so now we fire off a query that supports pagination, with page, perPage, and sort or search params. The backend is fine. The problem is in the front end, getting this working with a pagination widget.

I am trying to use ember-cli-pagination for the pagination widget. It requires a dedicated Controller (actually ArrayController, deprecated) and a dedicated Route for the model. I would be happy to use something else if something else would work.

The models:



Region = DS.Model.extend
    …
    locations: DS.hasMany 'location', async: true, inverse: null






    Location = DS.Model.extend
        …
        region: DS.belongsTo 'region', async: true, inverse: null


The locations are displayed in a component called ‘store-scorecard’, which is specified on index.hbs:



    


and here is within the component. You can see the locations are specified here and the ember-cli-pagination component is included with the page-numbers element.



    
        
    
    ...
    
        
    


There is one route and one controller, the IndexRoute and IndexController. The locations query had always been done from within the store-scorecard component, i.e.,



    StoreScorecardComponent = Ember.Component.extend
        ...
        locations: Ember.computed 'area', 'region', ->
            lowestRegion = @get('lowestRegion')
            lowestRegion.get 'locations'
        lowestRegion: Ember.computed 'area', 'region', ->
            @get('area') || @get('region')
        hasPagedLocations: Ember.computed 'locations.[]', ->
            @get('locations.length') > 0


I modified it to do the query in the component using a dedicated injected controller:



    StoreScorecardComponent = Ember.Component.extend
        store: Ember.inject.service()
        locationsIndexController: Ember.inject.controller('locations.index')
        ...
        locations: Ember.computed 'area', 'region', ->
            @get('store').query('location',
                region_id: @get('lowestRegion.id')
                page: @get('locationsIndexController.page')
                per_page: @get('locationsIndexController.perPage')


This runs the right query if you hard-code it (e.g., specify page: 1, per_page: 7), but because the locationsIndexController has no data, it can't construct the right query from controller data. The ember-cli-paginator component never gets its data and just as importantly, it doesn't set the page or totalPages values on the controller.

I have the same problem whether I make it a LocationsController or a LocationsIndexController or a RegionLocationsController (with corresponding routes). When I create these, we never hit that code. The LocationIndexController never has data, even hard-coded data. If I take the query out of the component and put it in the dedicated route (e.g., LocationsIndexRoute), we never hit that route so it never makes the query. So how should I set up this architecture, and how should I ensure that the right route and controller get used for the hasMany relationship?

Thanks in advance.




Aucun commentaire:

Enregistrer un commentaire