Ember cp-validations - belongsTo validation


#1

I didn’t find the answer in the examples provided in ember-cp-validation dummy app as well in their presentation.

I have to validate a language in the following model:

# models/shop-language.js

import DS from 'ember-data';
import { validator, buildValidations } from 'ember-cp-validations';

const Validations = buildValidations({
  language: {
    description: 'Language',
    validators: [validator('ds-error'), validator('presence', true)]
  },

  shop: {
    description: 'Shop',
    validators: [validator('ds-error'), validator('presence', true)]
  },
});

export default DS.Model.extend(Validations, {
  shop: DS.belongsTo('shop', { async: true }),
  language: DS.belongsTo('language', { async: true }),
  modifiedBy:  DS.attr('string')
});

On which property should I use v-getin the template if I load 2 models from my route:

#routes/shop-languages.js

model() {
    return RSVP.hash({
      shopLanguages: this.store.query('shop-language', { shop_id: this.get('currentShop.shop').get('id')}),
      languages: this.store.findAll('language')
    });
  },

Here is the template:

#templates/shop-languages.hbs
...
{{#each model.shopLanguages as |shopLang|}}
        <li class="list-group-item">
          {{shopLang.language.tag}}
          <button type="button" class="btn btn-danger btn-sm" disabled={{isDeleteButtonDisabled}} {{action "deleteLanguage" shopLang}}>
            <span class="oi oi-trash"></span>
          </button>
        </li>
      {{/each}}

  <form {{action "saveLanguage" aLanguage on="submit"}} class="form-inline">

          {{#if showLanguageError}}
            <div class="alert alert-danger">
              {{v-get aLanguage 'id' 'message'}}
            </div>
          {{/if}}

          <div class="col-sm-2">
            {{#power-select
              class="form-control"
              placeholder=placeholderText
              selected=aLanguage
              options=model.languages
              searchField="tag"
              noMatchesMessage=(t 'components.language.labels.not.found')
              onchange=(action (mut aLanguage))
              focus-out=(action (mut showLanguageError) true)
              as |language|
            }}
            {{language.tag}}
            {{/power-select}}
          </div>

<div class="form-check sm-2">
            <button type="button" type="submit" class="btn btn-success btn-sm">
              <span class="oi oi-plus"></span>
              {{t 'buttons.add'}}
            </button
...

Here is how I tried to save a newly added language in the route:

# routes/shop-languages.js

actions: {
...
  async saveLanguage(aLanguage) {
   ...
  try {
        await shopLanguage.save();
        controller.set('aLanguage', '');
        route.get('flashMessages').success(route.get('i18n').t('flash.language.added'));
        route.refresh();
      } catch(response) {
        let error = response.errors[0];
        console.log('+++++ in CATCH block error: ' + error);
        if (error.status !== "422") {
          throw response;
        }
      }

It prints the error to the console but displays nothing in the template … :frowning: The response I get from Rails backend if language is not selected:

{"message":"Couldn't find Language"}

Should parse in some way this message to be able to display it ? And the error object is as follows:

{status: "404", title: "The backend responded with an error", detail: "[object Object]"}

Thank you.


#2

A few things stand out as possibly wrong:

  1. showLanguageError is not set to a truthy value so the error message is not going to be rendered.
  2. You have {{v-get aLanguage 'id' 'message'}} in the template but the validation is not set up on the id property of aLanguage.
  3. I suppose aLanguage is a ShopLanguage but the code snippets don’t tell us that.

HTH


#3

Even if I remove ifcondition (this would enable displaying errors on the form display), nothing happens. That’s why I wonder what is the syntax to use when calling v-get:

# extact from RARWE book, page 291.

{{v-get model 'email' 'message'}}

All the provided use cases suppose to have ONE model defined in the route (like creating a User or a Post, for example).

aLanguage is an instance of Language model to be selected from the drop-down list (value to submit -> language.id, displayed value -> language.tag.

As I described earlier, the relations are defined as follows between Shop, ShopLanguage and Language models:

Shop: hasMany ShopLanguages
ShopLanguage: belongsTo Shop
ShopLanguage: belongsTo Language

You can see how it looks in the below screenshot.


#4

It doesn’t matter what your model is in the corresponding route. What matters is which object you added the validations onto that you’re checking.

v-get is just a nifty helper to prevent you from having to write lengthy expressions (see [the relevant page from the docs here).

So {{v-get model 'email' 'message'}} desugars to {{model.validations.attrs.email.message}}. In your case, {{v-get aLanguage 'id' 'message'}} is equivalent to {{model.validations.attrs.id.message}} which might not be what you want – unless you added a validation to the id property.