Debugging Ember

(without tears)

@vaidehijoshi

💕

💕

community

documentation

easy to use

...most of the time


Debugging

🐞

🐝

It's hard.

And frustrating.

Maybe I should give up?​

get       stuck

un

let's debug together!

Bug #1

🐛

😮

wait...what!?

narrow down the             of the problem

scope

the view

<h3>Recipes</h3>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Date</th>
    </tr>
  </thead>

  <tbody>
    {{#each sortedRecipes key='id' as |recipe|}}
      <tr>
        <td>
            {{#link-to 'recipe' recipe}}{{recipe.name}}{{/link-to}}
        </td>
        <td>
            {{time-format recipe.published_at 'l'}}
        </td>
      </tr>
    {{/each}}
  </tbody>
</table>

<hr>

<button {{action "newRecipe"}}>New Recipe</button>

👍

{{#link-to 'recipe' recipe}}
    {{recipe.name}}
{{/link-to}}

👍

the route

it's not the view.

maybe it's

// router.js

import Ember from 'ember';

Router.map(function() {
  this.route('recipe', { 
    path: '/recipe/:id' 
  });
});

dynamic segment

// recipe.js

import Ember from 'ember';

export default Ember.Route.extend({
});

the model

what does our route have access to?

where

             does it get access to it?

// recipe.js

import Ember from 'ember';

export default Ember.Route.extend({




});
// model hook!
model(params) {


    return this.store.find('recipe', params.id);
}
return a promise


Ember Data record
javaScript object
javaScript array
model(params) {
    debugger;

    return this.store.find('recipe', params.id);
}

yah yah yah, but will it work?

(also: how does it work?)

and when we refresh:

🎊

in our ember inspector:

import Ember from 'ember';

export default Ember.Route.extend({
  // model(params) {
    // return this.store.find('recipe', params.id);
  // }
});

so.

what's different?

where did we start?

the view

1/

   link-to

2/

   the route directly

documentation is our friend.

our route never knew how to get its model!

🙊

model hooks don't

fire when using

link-to helpers

🐛

Bug #2

🐜

Ember Meetup

Party Supplies

Party Supplies

1. Avocados

2. Pepper Jack Cheese

😱

why are our model properties wrong?

where do model properties come from?

the route

import Ember from 'ember';

export default Ember.Route.extend({
  model() {
    return this.store.find('grocery-list', params.id);
  }
});
import Ember from 'ember';

export default Ember.Controller.extend({
  name: null,
  items: null
});

Party Supplies

1. Avocados

2. Pepper Jack Cheese

our controller had values set at least once.

maybe we need to set them again?

             does a controller get its properties from?

where

...are we setting them correctly?

// grocery-list.js

import Ember from 'ember';

export default Ember.Route.extend({
  model(params) {
    return this.store.find('grocery-list', params.id);
  },

  setupController(controller, model) {
    this._super(controller, model);
  }
});
setupController(controller, model) {
    this._super(controller, model);

    controller.setProperties(
      model.getProperties([
        'name',
        'items'
      ])
    );
}

find model

pull values from it

set them on our controller

Ember Meetup

Party Supplies

Ember Meetup

Tomster food!

we never told our controller to set its properties!

🙊

controllers are singletons

persisted state

🐜

controllers are singletons

routeable components!

controllers are singletons

Bug #3

🐌

😭

what do we have

              to?

access

what's being passed in?

{{recipe-editor recipe=model afterDestroy='afterDestroy'}}

where do they come from?

import Ember from 'ember';

export default Ember.Route.extend({
  model(params) {
    return this.store.find('recipe', params.id);
  },

  actions: {
    afterDestroy() {
      this.transitionTo('recipes');
    }
  }
});
<button {{action 'deleteRecipe'}}>
    Delete
</button>

how is it being passed?

import Ember from 'ember';

export default Ember.Component.extend({
    recipe: null,

    saveRecipe() {
        // logic to save recipe
    },

    deleteRecipe() {
        const recipe = this.get('recipe');

        if (confirm('Are you sure?')) {
            recipe.destroyRecord().then(() => {
                afterDestroy();
            });
        }    
    }
});
{{recipe-editor recipe=model afterDestroy='afterDestroy'}}
deleteRecipe() {
    const recipe = this.get('recipe');

    if (confirm('Are you sure?')) {
        recipe.destroyRecord().then(() => {
            afterDestroy();
        });
    }    
}
this.afterDestroy();

this.sendAction('afterDestroy');
afterDestroy();

👎

🚫

deleteRecipe() {
    const recipe = this.get('recipe');

    if (confirm('Are you sure?')) {
        recipe.destroyRecord().then(() => {
            this.sendAction('afterDestroy');
        });
    }    
}

🎉

// recipe-editor/template.js

<recipe-editor recipe=model destroy={{action 'afterDestroy'}}>
// recipe-editor/component.js

export default Ember.Component.extend({
  actions: {
    deleteRecipe() {
      const recipe = this.get('recipe');

      recipe.destroyRecord().then(() => {
         this.attrs.destroy();
      }
    }
  }
});

angle-bracket way!

actions are fired on our current context

 

🐌

developing with ember:

superpowers!

Computers

 ¯\_(ツ)_/¯ 

understand what's happening in our code?

not cry while debugging?

understand what's happening in our code?

🐞

getting stuck.

getting unstuck.

asking             questions!

all the

     check our assumptions

     narrow down the scope of the problem

     figure out what we have access to

     lean on resources + docs

1/

2/

3/

4/

code's

point of view

frustrated

💖

fun

frustrated

Thanks!

@vaidehijoshi

🐞

Made with Slides.com