1

I'm building an Aurelia app that uses "Models" for every type of data object.

All my Models look something like this:

export class Item {
    id = null;
    name = '';
    description = '';

    constructor (data) {
        Object.assign(this, data);
    }
}

And I later create objects like this:

export class SomeViewModel {
    activate () {
        this.myItem = new Item({
            name: 'My Item!', 
            description: 'This is my item. It will be initialized with these properties.'
        });
    }
}

I got the Object.assign() bit from an article I read and it works really well. It allows me to create new items using data from the server, or if I want an empty Item I simply don't pass in anything.

Now I've reached a point where I need my model to have access to another class so I'm using Aurelia's Dependency Injection like this:

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';

@inject(Router)
export class Item {
    id = null;
    name = '';
    description = '';

    constructor (router, data) {
        this.router = router;
        Object.assign(this, data);
    }

    get permalink () {
        return window.location.protocol + '//' + window.location.host + this.router.generate('item', {itemId: this.id});
    }
}

Now my problem is this; how do I create a new Item() without passing in the Router myself? I guess switching the order of argument to constructor() would do the trick but that doesn't seem to work with Aurelia?

And I don't want to have to do this every time I create a new Item:

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';

@inject(Router)
export class SomeViewModel {
    constructor (router) {
        this.router = router;
    }

    activate () {
        this.myItem = new Item(this.router, {
            name: 'My Item!', 
            description: 'This is my item. It will be initialized with these properties.'
        });
    }
}

Surely there must be a better way to solve this?

powerbuoy
  • 12,460
  • 7
  • 48
  • 78
  • Just an idea: create an item factory service that you can pass around (inject) that you can call to create new items. – R. Richards Aug 19 '16 at 13:14

1 Answers1

2

Use the Factory resolver. Here's an example: https://gist.run?id=46642ac54893186067e7cd890d6722a3**

import {inject, Factory} from 'aurelia-dependency-injection';
import {MyModel} from './my-model';

@inject(Factory.of(MyModel))
export class App {
  message = 'Hello World!';

  constructor(createModel) {
    let model = createModel('my data');
  }
}

my-model.js

import {inject} from 'aurelia-dependency-injection';
import {EventAggregator} from 'aurelia-event-aggregator';

@inject(EventAggregator)
export class MyModel {
  constructor(eventAggregator, data) {
    console.log(eventAggregator, data);
  }
}
Jeremy Danyow
  • 26,470
  • 12
  • 87
  • 133
  • Ok thanks, could you explain a little more how this works? I'm not a huge fan of the extra code this requires tbh, but if this is the way to do it I guess I have no choice.. – powerbuoy Aug 19 '16 at 13:40
  • Would you say adding a method `setData()` to every one of my models is a worse solution? It would at least allow me to keep using pretty much the same code, only I'd do `this.myItem = new Item(); this.myItem.setData('my data')` – powerbuoy Aug 19 '16 at 13:41
  • there's friction with this kind of approach- you may want to step back, and consider not mixing the data with your model classes and instead build classes that act on the data without becoming it. For example, what if you had 100 instances of a data item. Do you want to instantiate 100 model instances or one instance of a something that can act on the 100 data item instances? – Jeremy Danyow Aug 19 '16 at 15:10
  • Well my idea was at least that every single item should be its own Item instance. But I might be doing it wrong? I also have a service for each model that handles all server communication. It usually goes like `ItemService.getItemsBySomeParams()` and then the `ItemService` fetches data and instantiates one `Item` object per well .. item – powerbuoy Aug 20 '16 at 11:55
  • Noticed now that you've answered this very question before :) http://stackoverflow.com/questions/34793723/assisted-injection-in-aurelia. Was really hoping there'd be a smoother way of achieving this. I'm not a huge fan of the `Factory` solution as I'd need to change _a lot_ of my code. I'm also not really a fan of adding a `setData()` method to every Model because that would prevent me from one-lining instantiation of items... What if I simply ignore the DI and just create a `new Router()` in my model. Is that extremely bad practice? – powerbuoy Aug 22 '16 at 10:14
  • One final thing and I'll stop bothering you :P Is there any performance loss from using `Factory.of`? I'd like my code to be consistent so even though this is only needed for one model as of right now, I'd prefer to update all my services to create their model instances this way. Unless of course it's bad for some reason. – powerbuoy Aug 22 '16 at 10:26