Assertion Failed in addTodo method

Hello everyone again! I got an issue :cry: . When i call addTodo method on button click and an error is thrown;

todos.js: ` import Route from “@ember/routing/route”;

import { action } from “@ember/object”;

export default class TodosRoute extends Route {

todos = [

    {id: 1, title: "Купить хлеб", completed: false},

    {id: 2, title: "Купить масло", completed: false},

    {id: 3, title: "Купить молоко", completed: false}


model() {

    return this.todos;



addTodo() {

    this.todos.push({id: 4, title: "Купить печенье", completed: false});


} `

todos.hbs: ` {{page-title “Todos”}}

<h1>All Todos</h1>

<div class="add-todos">



    {{#each @model as |todo|}}







<button type="button" {{on 'click' this.addTodo}}>Add Todo</button>

{{outlet}} `

issue: `Uncaught Error: Assertion Failed: You must pass a function as the second argument to the “on” modifier, you passed undefined. While rendering:

this.addTodo at assert (index.js:172) at OnModifierState.updateFromArgs (index.js:7161) at OnModifierManager.install (index.js:7388) at runtime.js:4712 at track (validator.js:826) at TransactionImpl.commit (runtime.js:4711) at EnvironmentImpl.commit (runtime.js:4813) at inTransaction (runtime.js:4838) at InteractiveRenderer._renderRoots (index.js:8563) at InteractiveRenderer._renderRootsTransaction (index.js:8615)`

So the TLDR here is that the action is defined on the route, but when you reference this in the template you’re actually referencing the route controller and not the route. Controllers are kind of a legacy holdover and this is a common tripping point because it’s one of the things that keeps route/template from being directly analogous to component/template.

With a route you have 3 parts instead of just 2:

  • the route, which manages routing state and the model
  • the controller, which handles the state and template bindings for the route
  • the template, which renders the route content

The important thing to remember is that the controller is all that the template can “see”, and it holds all backing state and actions that the template references. So to solve your problem you should move the addTodo action from the route to the controller. Another slightly weird thing about controllers is that they have the model auto-injected into them by a route hook called setupController. So the controller should also have access to the model via this.model.

Anyway, controllers have been on the chopping block for a very long time but it sounds like they may finally be deprecated soon once their last responsibility is taken care of (query param bindings). But for now it’s something we all have to live with. Hope that all makes sense, and definitely feel free to ask follow ups! Also for reference the guides page on Controllers may help

EDIT: for best code formatting in this board you can use markdown code blocks by wrapping your code in triple backticks ```

EDIT: for best code formatting in this board you can use markdown code blocks by wrapping your code in triple backticks ```

ok, I’ll consider

Thanks for answer again! Bye!