1
votes

I'm creating a basic store using ember with products and a shopping bag. I'm using LocalStorage as the adapter for the shopping bag so the user can come back to a cart with products they've added previously. At any one time, there should only be one shopping bag. Right now, I've set up a checker in the application route on activate to see if there's already a bag saved. If not, create one.

I also want to set-up the model correctly for it to be used in the controller and in templates. Here's my application route"

var ApplicationRoute = Ember.Route.extend({
  activate: function() {
    var store = this.store;
    store.find('bag').then(function(bags) {
      var existing_bag = bags.get('firstObject');
      // If there isn't already a bag instantiated, make one and save it
      if(typeof existing_bag === 'undefined') {
        var new_bag = store.createRecord('bag');
        new_bag.save();
      }
    });
  },
  model: function() {
    return this.store.find('bag');
  },
  setupController: function(controller,model) {
    controller.set('content', model);
  }
});

export default ApplicationRoute; 

Here is my bag model:

import DS from 'ember-data';
import Ember from "ember";

export default DS.Model.extend({
  products: DS.hasMany('product', {async: true}),
  bagProducts: DS.hasMany('bagProduct', {async: true}),
  productCount: Ember.computed.alias('products.length')
});

In my controller, I'd like to check if the bag has products in it so I can display a product count:

import Ember from "ember";

export default Ember.ArrayController.extend({
  bag: Ember.computed.alias("content"),
  cartHasProducts: function() {
    var bag = this.get('bag').objectAt('0');
    return bag.get('productCount') > 0;
  }.property('[email protected]')
});

And my template:

<div id="bag" class="js-btn" {{action "showModal" 'bag-modal' model}}>
  <i class="icon ion-bag"></i>
  <p class="label">Your Bag</p>
  {{#if controller.cartHasProducts}}
    <div class="count">
      <span>{{productCount}}</span>
    </div>
  {{/if}}
</div>

This works, but only after I use objectAt('0') to get the first instance of the bag. Shouldn't content just return the one instance of the bag? Is there a way to set up the model to just return the one current instance? What am I doing wrong?

I really really appreciate your help!

1

1 Answers

2
votes

This could be a solution: http://codepen.io/szines/pen/Aufmp?editors=101

(Should work with LocalStorage as well, above example uses FixtureAdapter.)

You can download both models in the store with RSVP, and in afterModel, you can check, bag already exist or not. If not, you can create one.

You can map your main model and your secondary model in setupController, so they gonna be exist in Controller and in views.

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return Ember.RSVP.hash({
      bagModel:        this.store.find('bag'),
      productList:     this.store.find('product')
    })
  },

  afterModel: function(model, transition) {
    if (model.bagModel.get('length') < 1) {
      model.bagModel = this.store.createRecord('bag');
    }
  },

  setupController: function(controller, model) {
    var productList = model.productList,
        bagModel    = model.bagModel;
    model = model.bagModel;
    this._super(controller, model);
    controller.set('productList', productList);
  }
});

Because you have only one bag as main model, better if you use ObjectController.

Controllers and models:

App.IndexController = Ember.ObjectController.extend({

  productCount: Ember.computed.alias('model.products.length'),

  actions: {
    addProduct: function(product) {
      this.get('model').get('products').pushObject(product);
    }
  }
});

App.Bag = DS.Model.extend({
  products: DS.hasMany('product', {async: true}),
});

App.Product = DS.Model.extend({
  name: DS.attr('string'),
});

App.Bag.FIXTURES = [];

App.Product.FIXTURES = [
  {id: 1, name: 'First Product'},
  {id: 2, name: 'Second Product'},
  {id: 3, name: 'Third Product'}
]

and the index template:

Number of products: {{productCount}}

{{#each productList}}
  <button {{action 'addProduct' this}}>Add {{name}}</button>
{{/each}}