Search code examples
javascriptaurelia

In Aurelia, what is the best way to do similar components?


Suppose we have two components that show similar data.

UnfilteredList - Calls the API with no filtering FilteredList - Calls the API with parameters to filter data

UnfilteredList.html looks much like FilteredList.html UnfilteredList.js looks almost identical to FilteredList.js

In our routes, we have both routes defined.

            {name: 'UnfilteredList', route: routes.UnfilteredList, isDisabled: false},
            {name: 'FilteredList', route: routes.FilteredList, isDisabled: false},
// More routes here

So is there a better way to do this to avoid duplicating code?

Edit: Update

I found out that if you want to use the same moduleId for two routes you can. Inside the module you have to do an import and add a method.

import {activationStrategy} from 'aurelia-router';

determineActivationStrategy()
{
    return activationStrategy.invokeLifecycle;
}

You can then use the params and routeConfig parameters in your activate method. Each route needs a unique name which you can then key off of to filter your data.

async canActivate(params, routeConfig)
{
    try
    {
        this.name = routeConfig.name;
    }
    catch (error)
    {
        this.errorMessage = error;
    }
}

Solution

  • There are a number of ways you could structure this, but the way I'd do it is to have one list route defined as follows:

    export class App {
        configureRouter(config, router) {
            this.router = router;
            config.title = 'Aurelia';
            config.map([
            { route: ['', 'home'], name: 'home', moduleId: 'index' },
            { route: 'list', name: 'list', moduleId: 'list',  nav: true },
            ]);
        }
    }
    

    This will enable a route like http://localhost/list?category=a&country=Australia

    In list.js view-model file, you could then access the query parameters specified in your route:

    things.js

    import {bindable, inject} from 'aurelia-framework';
    import {ThingApi} from '../../services/thing-api';
    
    @inject(ThingApi)
    export class List{
    
        constructor(thingApi){
            this.thingApi = thingApi;
        }
    
        activate(params, routeConfig) { 
            this.category = params.category;
            this.country = params.country;
            this.loadThings();
        }
    
        filter(){
            this.loadThings();
        }
    
        loadThings(){
            this.thigApi.getThings(this.category, this.country).then(things => {
                this.things = things;
            });
        }
    
    }
    

    things.html

    <template>
      <input name="category" value.bind="category"></input>
      <input name="country" value.bind="country"></input>
      <button click.delegate="filter()"></button>
      <hr/>
      <table>
        <tr repeat.for="thing of things">
           <td>${thing.category}</td>
           <td>${thing.country}</td>
        </tr>
      </table>
    </template>