Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

field.template(..., true) doesn't work in Embedded Entities view #1158

Open
RichardBradley opened this issue Jul 20, 2016 · 2 comments · May be fixed by #1170
Open

field.template(..., true) doesn't work in Embedded Entities view #1158

RichardBradley opened this issue Jul 20, 2016 · 2 comments · May be fixed by #1170

Comments

@RichardBradley
Copy link
Contributor

When using the "Embedded Entities" edit form, the field.template(x) function works fine to set a custom value template, but the field.template(x, true) function appears to have no effect.

To reproduce:

  • open this Plunkr demo: http://plnkr.co/edit/YeOBmuIqqAGEcBGINtIw?p=preview

  • click on "John" on the dashboard

  • click "add new children"

  • I have added the following fields to "user" and "child" (see script.js lines 45 - 58)):

        nga.field('custom value template')
          .template("custom value text"),
    
        nga.field('custom row template')
          .template("custom row text", true),
    

Expected behaviour:

I'd expect both the "user" form and the "child" form to have:

  • one row which has a label "custom value template" and a value "custom value text"
  • one row with just the text "custom row text" (no label)

Observed behaviour:

The user form has the above behaviour, but the child form has:

  • one row which has a label "custom value template" and a value "custom value text"
  • one row with a label "custom row template" and a text box
@RichardBradley
Copy link
Contributor Author

The edit.hml and create.html templates where fields are instantiated use a "compile" directive to replace the row with the "template()" of the field, if "template(..., true)" has been called on that field:

    <div ng-repeat="field in ::formController.fields track by $index" compile="::field.getTemplateValueWithLabel(entry)">
        <ma-field field="::field" value="entry.values[field.name()]" entry="entry" entity="::entity" form="formController.form" datastore="::formController.dataStore"></ma-field>
    </div>

The corresponding code in maEmbeddedListField.js does not, hence this bug:

    <div class="form-field form-group" ng-repeat="field in ::fields track by $index">
        <ma-field field="::field" value="entry.values[field.name()]" entry="entry" entity="::targetEntity" form="formName" datastore="::datastore()"></ma-field>
    </div>

However, the obvious fix of applying "compile" in both places has a problem in that the "default" template string differs between the two contexts. In the first context, the default template is the "<ma-field" string as seen above and listed in the docs. In the second context, the default template is similar, but has different attribute values.

I think this will make "template()" tricky to use correctly. However, fixing that issue is much harder and feels out of scope here.

RichardBradley added a commit to RichardBradley/ng-admin that referenced this issue Aug 3, 2016
RichardBradley added a commit to RichardBradley/ng-admin that referenced this issue Aug 3, 2016
RichardBradley added a commit to RichardBradley/ng-admin that referenced this issue Aug 3, 2016
@RichardBradley
Copy link
Contributor Author

RichardBradley commented Aug 3, 2016

I have created a PR which applies the obvious fix here.

As noted above, there is still a bit of an ugly API here, as the the "default" template string differs between the two contexts.

If I want to be able to show / hide edit rows based on the entity values, like http://stackoverflow.com/questions/35934085/ng-admin-how-to-show-different-fields-according-to-users-selection then I need to change the template based on whether the field is "embedded" or not.

Let's say I want to write a decorator named "showEditCreateIf" which will show/hide an edit/create field based on a field value. Using the same example as the the Field Configuration doc page:

post.editionView()
      .fields([
          nga.field('category', 'choice')
              .choices([
                  { label: 'Tech', value: 'tech' },
                  { label: 'Lifestyle', value: 'lifestyle' }
              ]),
          nga.field('subcategory', 'choice')
              .choices(function(entry) {
                  return subCategories.filter(function (c) {
                      return c.category === entry.values.category;
                  });
              })
              // display subcategory only if there is a category
              .showEditCreateIf("entry.values.category"),
      ]);

Here's a decorator I'm currently using that lets me write code like that, but it's ugly for the reason discussed above:


// Overrides for admin-config/lib/Field/Field.js
myapp.config(function(NgAdminConfigurationProvider) {

    var fieldProto = Object.getPrototypeOf(NgAdminConfigurationProvider.field(""));

    // Use this to add an "ng-if" to the field row in edit / create view.
    // `entry.values[x]` can be used to test the current value of entity properties
    //
    //   e.g. to show subcategory only if there is a category
    //     nga.field('subcategory', 'choice')
    //        .showEditCreateIf('entry.values.category')
    //
    fieldProto.showEditCreateIf = function(expressionStr) {
        if (!this.template()) {
            throw "You cannot use both `showEditCreateNgIf` and `template`";
        }

        this.template(function(entry) {

            var maField = document.createElement('ma-field');

            if (entry._entityName) {
                // This is the standard template, from
                //     ng-admin/Crud/form/edit.html
                // and ng-admin/Crud/form/create.html
                maField.setAttribute('field', '::field');
                maField.setAttribute('value', 'entry.values[field.name()]');
                maField.setAttribute('entry', 'entry');
                maField.setAttribute('entity', '::entity');
                maField.setAttribute('form', 'formController.form');
                maField.setAttribute('datastore', '::formController.dataStore');
            } else {
                // This is the standard template when the field is used
                // in an embedded entity context
                // See ng-admin/Crud/field/maEmbeddedListField.js
                maField.setAttribute('field', '::field');
                maField.setAttribute('value', 'entry.values[field.name()]');
                maField.setAttribute('entry', 'entry');
                maField.setAttribute('entity', '::targetEntity');
                maField.setAttribute('form', 'formName');
                maField.setAttribute('datastore', '::datastore()');
            }

            maField.setAttribute('ng-if', expressionStr);

            return maField.outerHTML;
        }, true);

        return this;
    };
});

Any ideas? Maybe the template() API needs a rethink, or do we need a native "showEditCreateIf" on fields?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants