TODO: Put in video showing the teachable screen with the upgrade course

Classic

Octane

Native Javascript Classes 

import Controller from '@ember/controller'

export default Controller.extend({

})
import Controller from '@ember/controller'

export default class MyController extends Controller {

}

Classic

Octane

Native Javascript Classes

import Controller from '@ember/controller'

export default Controller.extend({
    variable: 5,
    variableTwo: 8
})
import Controller from '@ember/controller'
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class MyController extends Controller {
    variable = 5
    variableTwo = 8
}

Classic

Octane

Native get statements 

import Controller from '@ember/controller'
import { computed } from '@ember/object';

export default Controller.extend({
    variable: 5,

    variablePlus(value){
        return this.get('variable') + value;
    },
})
import Controller from '@ember/controller'
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class MyController extends Controller {
    variable = 5

    variablePlus(value){
        return this.variable + value;
    }
}

Classic

Octane

Decorators

import Controller from '@ember/controller'

export default Controller.extend({
    variable: 5,

    variablePlus(value){
        return this.get('variable') + value;
    },

    actions: {
        addVariable(passedInVar){
            this.variablePlus(passedInVar);
        },
    }
})
import Controller from '@ember/controller'
import { action } from '@ember/object';

export default class MyController extends Controller {
    variable = 5

    variablePlus(value){
        return this.variable + value;
    }

    @action addVariables(passedInVar){
        this.variablePlus(passedInVar);
    }
}

Classic

Octane

Native getters

import Controller from '@ember/controller'
import { computed } from '@ember/object';

export default Controller.extend({
    variable: 5,

    variablePlus(value){
        return this.get('variable') + value;
    },

    doubleVariable: computed(function(){
        return 2 * this.get('variable');
    },

    actions: {
        addVariables(passedInVar){
            this.variablePlus(passedInVar);
        },
    }
})
import Controller from '@ember/controller'
import { action } from '@ember/object';

export default class MyController extends Controller {
    variable = 5

    variablePlus(value){
        return this.variable + value;
    }

    get doubleVariable(){
        return 2 * this.variable;
    }

    @action addVariables(passedInVar){
        this.variablePlus(passedInVar);
    }
}

Classic

Octane

Tracked Properties

import Controller from '@ember/controller'
import { computed } from '@ember/object';

export default Controller.extend({
    variable: 5,

    variablePlus(value){
        return this.get('variable') + value;
    },

    doubleVariable: computed('variable', function(){
        return 2 * this.get('variable');
    },

    actions: {
        addVariable(passedInVar){
            this.variablePlus(passedInVar);
        },
    }
})
import Controller from '@ember/controller'
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class MyController extends Controller {
    @tracked variable = 5

    variablePlus(value){
        return this.variable + value;
    }

    get doubleVariable(){
        return 2 * this.variable;
    }

    @action addVariables(passedInVar){
        this.variablePlus(passedInVar);
    }
}

Classic

Octane

Tracked Properties

import Controller from '@ember/controller'
import { computed } from '@ember/object';

export default Controller.extend({
    variable: 5,

    addValue(value){
        return this.get('variable') + value;
    },

    doubleVariable: computed('variable', function(){
        return 2 * this.get('variable');
    },

    actions: {
        addVariable(passedInVar){
            this.addValue(passedInVar);
        },

        changeVariable(newVar){
            this.set('variable', newVar);
        }
    }
})
import Controller from '@ember/controller'
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class MyController extends Controller {
    @tracked variable = 5

    addValue(value){
        return this.variable + value;
    }

    get doubleVariable(){
        return 2 * this.variable;
    }

    @action addVariables(passedInVar){
        this.addValue(passedInVar);
    }

    @action changeVariable(newVar) {
        this.variable = newVar;
    }
}

Classic

Octane

Async/await

import Controller from '@ember/controller'

export default Controller.extend({
    //...
    allAPICalls(){
        this.callAPI().then( () => {
            return this.callAPIAgain();
        }).then( ( => {
            return this.finalAPICall();
        }
    }
})
import Controller from '@ember/controller'

export default Controller.extend({
    //...
    async allAPICalls(){
        await this.callAPI();
        await this.callAPIAgain();
        await this.finalAPICall();
    }
})

Classic

Octane

Import NPM Packages

import Controller from '@ember/controller'

export default Controller.extend({
    //...
    async allAPICalls(){
        await this.callAPI();
        await this.callAPIAgain();
        await this.finalAPICall();
    }
})

Create a custom Ember addon or wait for someone else to create it

¯\_(ツ)_/¯

Classic

Octane

Glimmer Components

import Component from '@ember/component'

export default Component.extend({
    tagName: 'button',
    elementId: 'my-button',
    classNames: ['btn'],
    classNameBindings: ['isDangerous:dangerous'],
    attributeBindings: ['isDisabled:disabled'],

    isDangerous: false,
    isDisabled: false
})
import Component from '@glimmer/component'

export default class MyComponent extends Component {}
Click Me
<button
    id="my-button"
    class="btn {{if @isDangerous 'dangerous'}}"
    disabled={{@isDisabled}}>
        Click Me
</button>

Glimmer Components

Classic Octane
Default Binding Two-way One-way
Placement of passed variables Directly on component Args hash
Lifecycle hooks 13 2
Event Handlers 29 modifiers
Framework functions 21 none
Pass arbitrary html attributes No Yes

source: https://github.com/dhindurthy/ember-classicvsoctane-cheatsheet/blob/master/cheatsheet.md

Classic

Octane

Angle Bracket Invocation

{{example-component isDisabled=isDisabled
                    myVariable=myVariable}}
import Component from '@glimmer/component'

export default class MyComponent extends Component {}
Click For {{myVariable}}
<MyComponent disabled={{isDisabled}}
             @myVariable={{myVariable}} />
import Component from '@ember/component'

export default Component.extend({
    tagName: 'button',

    attributeBindings: ['isDisabled:disabled'],

    isDisabled: false
})
<button ...attributes>
    Click For {{@myVariable}}
</button>

Classic

Octane

Element Modifiers

<button {{action 'actionName'}}>
    Click Me
</button>
<button {{action 'actionName'}}>
    Click Me
</button>

<span {{tooltip-hover 'Click button to do things'}}>
    ?
</span>

<div {{arbitrary-modifier}}>
    Something
</div>

Pretty much just the action modifier

modifiers in addons + create your own

Classic

Octane

Other Stuff

jQuery

NO jQuery

(by default)

run loop

NO run loop

Octane differences

By Jeffrey Biles

Octane differences

  • 598