mercredi 1 juillet 2015

looping over an array returned from function

As you'll see in the answer to this SO question it is possible to loop with {{#each}} in a component template over the return value of a component function that is an array. For convience sake, I copy that code here at the very bottom.

I tried to do something similar. In my template, I use a component and pass it an object with key values

{{'my-comp' kvobject=mykvobject}}

In components/my-comp.js, I create a function that returns an array

   keyvalues: function(){
      var emberobj = this.get('kvobject');
   //note the object I'm interested in is wrapped in some emberarray or object that is at emberobj[0]; 
      var arr = [];
      for (var key in emberobj[0]){ 
          if(emberobj[0].hasOwnProperty(key)){
               var pair = key + ' : ' + emberobj[0][key];
               arr.push(pair)
           }
      }
      return arr; 

   }

In my component template templates/components/my-comp, I do

  {{#each pair in keyvalues}}
    {{yield}}
  {{/each}}

But this throws an array, saying the value that #each loops over must be an Array. You passed function keyvalues().

Question: why can't I loop over the array returned from the function as a type of computed property? Below, is the code from the linked-to answer that I modeled my code after.

App.IncrementForComponent = Ember.Component.extend({
  numOfTimes: function(){
    var times = this.get('times');
    return new Array(parseInt(times));
  }.property('times')
});

Component template:
<script type="text/x-handlebars" id="components/increment-for">
  {{#each time in numOfTimes}}
    {{ yield }}
  {{/each}}    
</script>

Component usage:
{{#increment-for times=2 }}
  <div>How goes it?</div>
{{/increment-for}}




Ember.js - How to resolve a computed property on a child before the child route is activated

I have a Parent-Child-Grandchild relationship that looks like this:

Course
    - has_many Questions

Question
    - has_many Answers

Answer

On my Question model I have a computed property answerCount. When I get to the questions route /courses/1/questions the computed property is evaluated, but not before when I'm in the course route /courses/1.

I want to show users the number of unanswered questions when they enter the course route. But I'm only able to do it at the questions route because that is when the async has_many answers relationship resolves.

How can I get information about the questions has_many answers relationship before the relationship resolves? Or, how can I force the relationship to resolve in the parent route /courses/1?

Please let me know what additional information I can provide.




ember.js: how to get name of controller / initializer / ect you are currently in?

I override Ember.deprecate() and Ember.warn() functions and I'm trying to understand where the warning / deprecation is coming from.

Problem is - I couldn't find any way to get the name of the controller / initializer / etc I'm called from, and generating an error to get the stacktrace return something like this:

at new Error (native)
at Error.EmberError (http://localhost:8000/static/assets/vendor.js:22707:21)
at Object.eval (eval at evaluate (unknown source), <anonymous>:1:9)
at Object.InjectedScript._evaluateOn (<anonymous>:895:55)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:828:34)
at Object.InjectedScript.evaluateOnCallFrame (<anonymous>:954:21)
at Object.Ember.default.deprecate (http://localhost:8000/static/assets/agent.js:50:4)
at Object.Registry.lookup (http://localhost:8000/static/assets/vendor.js:12173:26)
at Object.<anonymous> (http://localhost:8000/static/assets/vendor.js:59653:45)
at Object.__exports__.default [as load] (http://localhost:8000/static/assets/vendor.js:60876:20)"

Which is pretty much useless..

So my question - how do I tell "where I am", eg what top level object caused the warning? In the example above it was called from an initializer but I want to know which one (filename would be enough for me).

PS. in case you wondered: the params deprecate() get is a short warning string and sometimes a url which lead to the docs explaining about the deprecation.

Thanks




Sort hasMany products by id

I sideload products of a given category. The problem is that they are not sorted. I'd like to sort them by id and render the sorted products in a select.

How can I sort them?

app/category/model.js

import DS from 'ember-data';

export default DS.Model.extend({
  name: DS.attr('string'),
  products: DS.hasMany('product', { async: true })
});

route.js

import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
    return {
      category: this.store.find('category', 1)
    };
  }
});

template.hbs

{{view "select" prompt="All products"
       content=model.category.products
       optionLabelPath="content.name"
       optionValuePath="content.name"
       value=selectedProduct
       class="form-control"}}




Load hasMany products of a given category

How can I load only the products of a given category in the route.js? My current route.js loads the first category but all products. But I only want the products of the first category.

app/category/model.js

import DS from 'ember-data';

export default DS.Model.extend({
  name: DS.attr('string'),
  products: DS.hasMany('product', { async: true })
});

route.js

import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
    return {
      category: this.store.find('category', 1),
      products: this.store.find('product')
    };
  }
});




Wait for foundation modal dialog in acceptance test

During acceptance test, in order to simulate user interaction, the button on the foundation modal dialog should be clicked:

test('sets correct country name after manual lookup', function(assert) {
  visit('/sign-in');
  click('#country-name');

  Ember.run(function() {
    fillIn('#country-name', 'state');
    click('li:contains("United States")');
  });

  andThen(function() {
    assert.equal(find('#country-name').text(), 'United States');
    assert.equal(find('#country-code').text(), 1);
  });
});

but that doesn't work because of dialog appears after the code is executed -

Also I tried to wrap clicking in the Ember.run.scheduleOnce('afterRender', this, function(){ ... }} - no success either.




Shopping cart in EmberJS: trying to add product model to cart model

A complete newbie to Emberjs here and a sort of newbie to web development. I'm trying to build a very simple e-tailer website in order to get familiar with Ember. The process where I'm getting stuck is getting my product model to get added to cart.

The details of the project: emberjs: 1.13.2 ember-data: 1.13.4 ember-cli: 0.2.7

The backend is being mocked by ember-cli-mirage

The code is as follows:

models/product.js

import DS from 'ember-data';

export default DS.Model.extend({
  name: DS.attr('string'),
  description: DS.attr('string'),
  category: DS.attr('string'),
  price: DS.attr('number'),
  quantityInStock: DS.attr('number'),
  imageUrl: DS.attr('string')
});

models/item.js

import DS from 'ember-data';

export default DS.Model.extend({
  product: DS.belongsTo('product'),
  cart: DS.belongsTo('cart'),
  quantity: DS.attr('number'),
  subTotal: function() {
    return this.get('product').get('price') * this.get('quantity');
  }.property('product', 'quantity')
});

models/cart.js

import DS from 'ember-data';

export default DS.Model.extend({
  items: DS.hasMany('item')
});

controllers/products.js

import Ember from 'ember';

export default Ember.Controller.extend({
  needs: ['cart'],
  cart: Ember.computed.alias('controllers.cart'),
  actions: {
    addToCart: function(product) {
      this.get('cart').add(product);
    }
  }
});

controllers/cart.js

import Ember from 'ember';

export default Ember.Controller.extend({
  add: function(product) {

  }
});

What I can't figure out is how to get the cart controller to handle the action. I think the code is supposed to do this:

  1. find the cart model from the data store
  2. check to see if the item being added to the cart is already in the cart
  3. if it is: increment its property by 1
  4. if it is not: create a new item, make it belong to the cart, give it the product, give it a quantity of 1. Then, save it.
  5. Finally, add this item to the cart. Save the cart to the backend.

Some notes, thoughts & other problems

Note #1: I only have routes to handle product and cart on the backend (I don't see why I would handle item since it would be in the cart hash).

But, saving an item makes a call to the back-end. I'm guessing I should save the item in localstorage? Not sure how to go about doing that in the latest version of ember-data.

Note #2: I don't use any dynamic urls. all the products load on a single page. There are only two routes: products and cart.

Note #3: the item model is a line item.

Note #4: I'm not even sure if this is the best way to handle it. Should I just load multiple models on the product route. Would that simplify it?

I'm not sure if I should include any other code but the github is here:

ember-responsive-retailer

Thanks a lot!