lundi 25 janvier 2016

Ember approach for setting controller computed property from action

I'm new to Ember and trying to follow the Data Down Action Up approach with my controller acting as the main parent 'component' with a number of components sending actions up to the controller to set values on models that will eventually trickle back down new value to the components. I know controllers are going away but I need this controller to hold all the state if you will...

I'm struggling with my approach in that I want to set a number of computed properties on my controller that watch model properties. Most difficult seemingly is setting the value of one of these computed properties that needs to set some other property when an action fires. Here is some of my controller:

//controllers/groupPlanning.js

import Ember from 'ember';

export default Ember.Controller.extend({

    groups: Ember.computed('model.@each.groups', function(){
        return this.get('model').get('groups');
    }),

    enrollmentGroup: Ember.computed('groups', function(){
        this.get('groups').forEach(function(group) {
            if (group.name === 'Enrollment'){
                return group;
            }
        }):

    }),

    enrollmentGroupPercent: Ember.computed('enrollmentGroup', function() {
        var group = this.get('enrollmentGroup');
        return group.year * this.get('someOtherNumber');
    }),

   ...

    actions: {
        setGroupYear: function(year){
            var group = this.get('enrollmentGroup');
            group.set('year', year);
            group.save();
        }
    }

});

Aside from asking if this approach seems reasonable, I'm having a problem actually setting the value of enrollmentGroup in my action:

group.set('year', year);

which throws and error of

Uncaught TypeError: Cannot read property 'set' of undefined

Any pointers here would be appreciated. Thanks!




ember-simple-auth custom authorizer not called with ember-django-adpter

I am using ember-django-adapter with ember-simple-auth and have written the custom authorizer for token authentication. I am able to obtain the token from server but not able to inject it into the api requests using the adapter.

app/authorizers/application.js

import Ember from 'ember';
import Base from 'ember-simple-auth/authorizers/base';

const { service } = Ember.inject;

export default Base.extend({

  session: service('session'),

  init: function () {
    console.log('Intialize authorizer');
  },

  authorize(data, block) {
    const accessToken = data['access_token'];
    if (this.get('session.isAuthenticated') && !Ember.isEmpty(accessToken)) {
      block('Authorization', `Token ${accessToken}`);
      console.log("authorizer called with token: " + accessToken);
    }
  }
});

app/adapters/application.js

import Ember from 'ember';
import DRFAdapter from 'ember-django-adapter/adapter/drf';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';

const { service } = Ember.inject;

export default DRFAdapter.extend(DataAdapterMixin, {
  session: service('session'),
  authorizer: 'authorizer:application'

});

app/authenticators/token.js

import Ember from 'ember';
import Base from 'ember-simple-auth/authenticators/base';

export default Base.extend({
  serverTokenEndpoint: 'http://localhost:8000/ember-auth/',

  authenticate: function(email, password) {
    return new Ember.RSVP.Promise((resolve, reject) => {
      Ember.$.ajax({
        url: this.serverTokenEndpoint,
        type: 'POST',
        data: JSON.stringify({
          email: email,
          password: password
        }),
        contentType: 'application/json;charset=utf-8',
        dataType: 'json'
      }).then(function(response) {
        console.log('Got token: ' + response.token);

        Ember.run(function() {
          resolve({
            token: response.token
          });
        });
      }, function(xhr) {
        var response = xhr.responseText;
        Ember.run(function() {
          reject(response);
        });
      });
    });
  },

  invalidate: function() {
    console.log('invalidate...');
    return Ember.RSVP.resolve();
  }
});

Ember tries to transition to protected route but due to non injection of Authorization header the request fails with 403 error.

Any help is appreciated.




Ember destroyRecord on polymorphic record calls the wrong route

I have a polymorphic record type in my ember application. Posts has a polymorphic association called response, which can be a few kinds of response.

// post.js
import DS from 'ember-data';

export default DS.Model.extend({
  ...
  responses: DS.hasMany('response', { polymorphic: true })
});

The response model is the basis for all the other types.

// response.js
import DS from 'ember-data';

export default DS.Model.extend({
  post: DS.belongsTo('post'),
  message: DS.attr('string')
});

For example, a comment inherits from response.

// comment.js
import Response from '../models/response';

export default Response.extend();

This works perfectly for loading models using ember-data. It correctly connects to /responses on the Rails server for all types of responses.

However when I try to delete a record using record.destroyRecord() it sends the delete to /comments on the server, instead of /responses. Because this is a polymorphic record there is no comments route on the server.

Is there some other part of ember-data where I can indicate the record deletion should be polymorphic?




Ember.js/handlebars how to bind variable passed to a component to a model

Let's say I have a model called "Article" with only one property called "title"...

I could write hanblebars to edit the article property like this:

<span>Title</span><span>{{input value=title}}</span>

And Ember/handlebars magically binds the value of that input box to the "title" property value.

No problem there. But I am working on a project in which I will need to generate the handlebars code dynamically, based on a model definition model.

For example, I will not know there is a property called "title", but would have instead to loop into a "modelFields" list in the model definition model.

So, the handlebars will be something like this:

Looking at the code below:

{{#each modelField in modelFields}}
    <span>modelField.displayName</span><span>{{input value=modelField.propertyName}}</span>
{{/each}}

The result HTML for the "title" property will be:

<span>Title</span><span><input value="title"></span>

Now here is my question, is there a way to have the value coming dynamically from propertyName (title, in this example) to be handled by ember as a binding property title, instead of a string title?

To clarify, is there a way for the result of this:

{{#each modelField in modelFields}}
    <span>modelField.displayName</span><span>{{input value=modelField.propertyName}}</span>
{{/each}}

to be treated as this (title is a binding property):

<span>Title</span><span>{{input value=title}}</span>

instead of this (title is a string):

<span>Title</span><span><input value="title"></span>

?

I tried with views,components, with no luck.




Ember left nav creation

I need to create a left nav in ember that functions very much like the left nav on the ember website. I am currently on Ember 1.X which has poor serialization support for nested JSON. I started off with this data model which I do not believe will work with Ember 1.X:

var menuItems = [{
  id: 1,
  title: 'Payroll',
  children: { 
        'Child 1',
        'Child 2'
    }
  },{
    id: 2,
    title: 'Time & Attendance',
    children: { 
        'Child 1',
        'Child 2',
        'child 3'
    }
}];

I have my menu template.js built like this (*untested):

<div class="container-fluid">
  <div class="row">
    <div class="col-md-2">
        <ul class="navMenu nav list-unstyled">
          {{#each model as |menuItem|}}
            {{#if isActive}}
              <span {{action "makeInactive"}} class="">{{menuItem.title}}</span>
              <ul>
                {{#each child as |children|}}
                  <li><a href="#">{{child}}</a></li>
                {{/each}}
              </ul>
            {{else}}
              <span {{action "makeActive"}} class="">{{menuItem.title}}</span>
            {{/if}}
          {{/each}}
        </ul>
    </div>
    <div class="col-md-10">Will be content</div>
  </div>
</div>

This will sort of work, but I'll need some way to ensure only 1 element is active at a time.

Do I need to update to ember 2.X to do something like this?




TypeError: _ember.default.HTMLBars._registerHelper is not a function

I updated my app with some new packages. Now, I'm getting an error in my browser debugger console:

TypeError: _ember.default.HTMLBars._registerHelper is not a function

I launch ember server and none of my content displays in the generated index.html.

package.json

{
  "name": "MyApp",
  "version": "0.0.0",
  "description": "Small description",
  "private": true,
  "directories": {
    "doc": "doc",
    "test": "tests"
  },
  "scripts": {
    "start": "ember server",
    "build": "ember build",
    "test": "ember test"
  },
  "repository": "",
  "engines": {
    "node": ">= 0.10.0"
  },
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "broccoli-asset-rev": "2.4.2",
    "broccoli-merge-trees": "^1.1.1",
    "broccoli-static-compiler": "^0.2.2",
    "ember-cli-app-version": "^1.0.0",
    "ember-cli-babel": "^5.1.6",
    "ember-cli-bootstrap-datepicker": "0.5.5",
    "ember-cli-content-security-policy": "0.5.0",
    "ember-cli-dependency-checker": "^1.2.0",
    "ember-cli-htmlbars": "^1.0.2",
    "ember-cli-i18n": "0.0.6",
    "ember-cli-ic-ajax": "0.2.4",
    "ember-cli-inject-live-reload": "1.4.0",
    "ember-cli-inline-content": "0.4.0",
    "ember-cli-less": "1.5.3",
    "ember-cli-moment-shim": "0.7.3",
    "ember-cli-qunit": "^1.2.1",
    "ember-cli-uglify": "^1.2.0",
    "ember-data": "2.3.3",
    "ember-export-application-global": "1.0.5",
    "ember-infinity": "0.2.1",
    "ember-modal-dialog": "0.8.3",
    "ember-moment": "6.0.0",
    "ember-radio-button": "1.0.7"
  },
  "dependencies": {
    "ember-cli": "1.13.15",
    "ember-validations": "2.0.0-alpha.4"
  }
}

bower.json

{
  "name": "MyApp",
  "dependencies": {
    "ember": "2.3.0",
    "ember-cli-shims": "0.1.0",
    "ember-cli-test-loader": "1.1.3",
    "ember-load-initializers": "0.1.5",
    "ember-qunit": "0.4.7",
    "ember-qunit-notifications": "0.0.7",
    "ember-resolver": "~0.1.0",
    "jquery": "1.11.3",
    "loader.js": "ember-cli/loader.js#3.4.0",
    "qunit": "~1.17.1",
    "components": "git+http://ift.tt/1Pxz4nX",
    "ember-uploader": "0.3.11",
    "ember-cli-moment-shim": "~0.6.2",
    "bootstrap-datepicker": "~1.5.1",
    "lodash": "~4.0.1",
    "moment": ">= 2.10.6",
    "moment-timezone": ">= 0.2.5"
  },
  "resolutions": {
    "ember": "2.3.0",
    "qunit-notifications": "~0.1.0",
    "ember-cli-test-loader": "0.1.3",
    "ember-load-initializers": "0.1.5",
    "loader.js": "3.2.0",
    "ember-qunit": "0.4.7",
    "moment-timezone": "~0.2.5",
    "ember-qunit-notifications": "0.0.7",
    "moment": "~2.10.5",
    "qunit": "~1.17.1",
    "ember-cli-shims": "0.1.0"
  }
}

I went through and tried to update each package to the latest version. However, I had to revert some because of dependencies on earlier versions. The bower.json generated it's own "resolutions" which I do not know what it is or if it is correct.




Returning modules to a Specific Component Ember

I have a component in my app.

The component {{masonry-plugin}} is inside one of my templates called photography.hbs

this is the logic of the component

//components/masonry-plugin.js
import Ember from 'ember';

export default Ember.Component.extend({
  didInsertElement : function(){
    this._super();
    Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
  },

  afterRenderEvent : function(){
    var $grid = this.$('.grid').masonry({
      itemSelector: '.grid-item',
      percentPosition: true,
      columnWidth: '.grid-sizer'
    });
    // layout Isotope after each image loads
    $grid.imagesLoaded().progress( function() {
      $grid.masonry();
    });  
  }
});

The problem is that i do not know to pass the modules to my component template{{masonry-plugin}}

which is the following

<div class="grid">
    <div class="grid-sizer"></div>
    {{#each model}}
        <div class="grid-item">
          <img {{bind-attr src=imgLink}}>
        </div>
     {{/each}}
</div>

imgLink is the module record created in photography route consuming the flickr API.

How can i say to my component to return these models? Is there maybe an other better idea on how to do it? If i have static url the images src and components work, so i have to figure this problem out in order to get the img src model

I am using Ember 1.13.11