Technology and Me

Main menu

Tag Archives: emberjs

Today I want to talk about conventions and share something I’ve been doing as I’m working in my app that uses EmberJS for the front-end.

Warning: This post does assume a certain degree of familiarity with ember/ember-cli and I assume that you have all things installed necessary to run/build an ember app. There’s a full repository on github with the complete project, which I’ll reference from here.

We’re going to create a very simple app with components that have i18n, real-time validation, use DDAU (data down, actions up) and some baked-in conventions to make things more “robust”. It will look something like this:

Components with validation and i18n

The first thing is to create a new project using ember-cli (at the time of writing EmberJS is on version 2.9.1) on the terminal:

Ok, so now we have a DDAU compatible component, which is nice (see this commit).

Now let’s make things more interesting!

Conventions on i18n

Ideally if I need to show the same field of a given model, I would like to have the labels/placeholders all centralized in a localization file, so I’m going to do the following and put the following in my locales/en/translations.js (and the equivalent in /pt/translations.js) and not have to type them in the template every time.

export default {
'model': {
'person': {
'name': {
'label': 'Name',
'help': 'This name will be used throughout the application to display your name',
'placeholder': 'Person\'s complete name'
},
'age': {
'label': 'Age',
'help': 'This field is used to validate access to some parts of the app, must be 18 or older',
'placeholder': 'The age (in years)'
}
}
}
};

I mean, it’s kind of verbose, having to pass all that model.modelName.attribute.xxx over and over again, so I’m going to leverage conventions here. I know that my strings are in a translations file with the structure being:

We are going to leverage the fact that each DS.Model instance knows the model name (through constuctor.modelName) and create a helper method getTranslation which uses the model name and attribute name to get the translation using that structure we defined in the translations file (model.modelName.attribute).

Since we also pass the attribute name from the application template, we have everything we need. Just need to update the application template and remove the label and placeholder parameters:

And with this (see this commit), we finish the first part regarding conventions. We basically leverage a predefined structure (convention) in the translations file and the fact that each instance of a model knows the name of the model to retrieve all the values associated with a given attribute.

Part 2 – Preventing bugs/typos on attribute names using conventions

One of the things that I find a real problem is doing things like we did before while setting the value on the model:

Doing a set operation and passing a string like ‘name’ means that if we make a small typo on that ‘name’, we never find out about it until we go hunting a bug because some operation that depends on this value is having a weird behavior. This is a mistake I’ve done plenty of times, and the way I found to deal with my typos is the following:

I create a file in the utils folder of my app called person-utils.js in which I place the following content:

Real-time validation

The last step in this tutorial is having validation as you type. In order to do that we must define a set of validations as per ember-model-validator‘s documentation, so we change our model to have the following (age must be an integer over 18 and name a string over 4 characters long):

We use the “gt” helper for ember-truth-helpers for check if the model has errors on the attribute that is linked to this component and if so, we add the “has-error” class.

With this now we are capable of showing errors, but we’re missing something that triggers the validation process. Since I want to have “real-time” validation, I’m going to use the actions in the controller that update the model, to also validate the field which I’m typing on.

EmberJS is a really great framework which leverages a lot of conventions (especially when coupled with the excellent ember-cli tools), by adding a few more of our own conventions on top of this project I think we get even more value.

Just wanted to drop another quick post about how to conditionally import assets in ember-cli-build.js. I needed to do that in order to make ember-cli-page-object work in development mode.

Apparently there’s already an issue open on github about this situation, but since it’s a solution for the addon and not the user, I’m going to add it here (until a PR lands you have to do this). Since the ember-cli-build.js file is a regular javascript file you can simply drop these lines on it.

Just wanted to do a quick post about this error I got when developing an EmberJS Application and trying to test a component (via an Integration test). The following error occurred while running the test:

Error: Failed to execute 'setAttribute' on 'Element': '=' is not a valid attribute name.
at Error (native)
at DOMHelper.prototype.setAttribute (http://localhost:4200/assets/vendor.js:12027:13)
at Object.buildFragment (http://localhost:4200/assets/weldnote.js:24465:13)
at getCachedFragment (http://localhost:4200/assets/vendor.js:55321:29)
at Function.RenderResult.build (http://localhost:4200/assets/vendor.js:55044:20)
at render (http://localhost:4200/assets/vendor.js:55008:37)
at http://localhost:4200/assets/vendor.js:55799:11
at renderAndCleanup (http://localhost:4200/assets/vendor.js:55836:18)
at Object.block [as default] (http://localhost:4200/assets/vendor.js:55797:9)
at keywords.yield (http://localhost:4200/assets/vendor.js:54620:25)

I was trying to create an integration test for a component like the following (the default generated test, where I removed the block form assertion):

Can you spot the error? Look closely at the ‘data-test=’label’=>‘. Somehow I left that second ‘=‘ (equal) sign there and it doesn’t make HTMLBars fail the compilation but at runtime it blows up with this weird error.