Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

{{action}} link with transitionTo using relationship id

Tags:

ember.js

Given a view with a context like { id: 1, form_id: 5}, I want to create an {{action}} link to the form using the form_id.

My view code looks like:

<script type="text/x-handlebars" data-template-name="group">
  {{action showForm form_id href=true}}
</script>

And the action in my router looks like:

showForm: function(router, event) {
  var form_id = event.context;
  router.transitionTo('root.form', { id: form_id });
},

I get an error that reads:

Uncaught Error: assertion failed: You must specify a target state for event 'showForm' in order to link to it in the current state 'root.index'.

I'm guessing that the problem is with the way I'm setting up the context for transitionTo, but I haven't been able to figure out the correct solution.

Here is the full code to reproduce the problem:

<script type="text/x-handlebars" data-template-name="application">
  {{outlet}}
</script>

<script type="text/x-handlebars" data-template-name="group">
  {{action showForm form_id href=true}}
</script>

MyApp = Ember.Application.create({
  autoinit: false
});

MyApp.router = Ember.Router.create({
  root: Ember.Route.extend({
    index: Ember.Route.extend({
      route: '/',

      // Throws error: 
      //    You must specify a target state for event 'showForm' in 
      //    order to link to it in the current state 'root.index'
      //
      showForm: function(router, event) {
        var form_id = event.context;
        router.transitionTo('root.form', { id: form_id });
      },

      // Won't work because form deserialize finds id, not form_id 
      //showForm: Em.Route.transitionTo('root.form'),

      // This won't work either
      // showForm: Em.Route.transitionTo('root.form', { id: this.form_id }),        

      connectOutlets: function( router, context ){
        var group = Em.Object.create({ id:1, form_id: 5 });
        router.get( 'applicationController' ).connectOutlet( 'group', group );
      }
    }),
    form: Ember.Route.extend({
      route: '/form/:id',
      serialize: function( router, context ){
        return { id: context.id }
      },
      deserialize: function( router, context ){
        var form = Em.Object.create({ id: 5, name: 'my form' });
        return MyApp.Form.find( context.id );
      },
      connectOutlets: function( router, context ){
        // left out for fiddle example 
      }
    })
  })
});

MyApp.ApplicationController = Ember.Controller.extend({});

MyApp.GroupController = Em.ObjectController.extend({});
MyApp.GroupView = Em.View.extend({ templateName:  'group' });

MyApp.initialize(MyApp.router);​

And the cooresponding fiddle:

http://jsfiddle.net/jefflab/LJGCz/

like image 493
jefflab Avatar asked Nov 03 '22 09:11

jefflab


1 Answers

I was able to come up with an ugly solution to this problem using a computed property as the context of my action. The key snippets are:

<script type="text/x-handlebars" data-template-name="group">
  <a {{action showForm view.formHash href=true}}>go to form</a>
</script>

MyApp.GroupView = Em.View.extend({ 
  templateName:  'group',
  formHash: function() {
    return { id: this.get('controller').get('form_id') };
  }.property('form_id')
});

And the working fiddle is here:

http://jsfiddle.net/jefflab/pGv8u/

However, after talking to Tom Dale, it is clear that the "right way" to solve to solve this problem is by using materialized objects instead of id values. If you are using Ember data, this is a great use case for the "sideloading" belongsTo feature.

like image 63
jefflab Avatar answered Nov 11 '22 07:11

jefflab