Search code examples
ember.jsglimmer.js

Can console.log be passed in to test a Ember.js component from my application template?


I am building a simple button component and I would like to test that my click handler is working by passing in console.log (or some other function) into my component. This is in Ember 4.

app/components/eu-button.hbs looks like:

<button
  type={{ this.type }}
  class={{ this.colors }}
  ...attributes
  {{on "click" (fn @onClick) }}
>
  {{#if this.args.icon }}<FaIcon @icon={{ this.args.icon }} />{{/if}}
  {{ this.args.text }}
  {{ yield }}
</button>

and implementation is:

import Component from '@glimmer/component';

export default class EuButtonComponent extends Component {
  get type() { return "button"; }
  get colors() { return "various classes"; }
}

I am calling it from my app/templates/application.hbs like this:

<EuButton @text="Test" @icon="pencil" @onClick={{ fn console.log "test" }}/>

In the hopes that I could see the console print the word "test" on a button click. However, I'm getting:

Uncaught Error: Attempted to resolve a value in a strict mode template, but that value was not in scope: console

I have tried passing in @onClick={{ fn window.console.log "test" }} and @onClick={{ fn document.console.log "test" }} with similar errors.

I think my error is more a misunderstanding of JS that Ember (or Glimmer) so I'd appreciate any help on understanding that function's scope or, alternately, a function I could use in place of console.log in this way.


Solution

  • I don't think you can do it from the .hbs file. But if that's not your goal (which i doubt it is) then you can add a function called an action to your controller application.js (or wherever you call the component from; might be a containing component) file and there you'll be able to do whatever you want.

    import Controller from '@ember/controller';
    // add this decorator here
    import { action } from '@ember/object';
    
    export default class ApplicationController extends Controller {
      // here's your handler
      @action
      onClick(message) {
        console.log(message);
      }
    }
    
    

    then you'll be able to call it from the .hbs:

    <EuButton @text="Test" @icon="pencil" @onClick={{ fn this.onClick "test" }}/>
    

    Relevant reading: https://guides.emberjs.com/release/components/component-state-and-actions/#toc_html-modifiers-and-actions or even better https://guides.emberjs.com/release/in-depth-topics/patterns-for-actions/