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

How to validate nested keys? #110

Open
olivierlesnicki opened this issue Dec 1, 2016 · 18 comments · Fixed by #251
Open

How to validate nested keys? #110

olivierlesnicki opened this issue Dec 1, 2016 · 18 comments · Fixed by #251

Comments

@olivierlesnicki
Copy link

Given the following Ember.Object:

Ember.Object.create({
  title: 'Hello',
  contactNumber: {
    type: '07594378348',
    number: ''
  }
})

How do I define validations to validate the contactNumber.number field?

{
  title: validatePresence(true),
  contactNumber: ... ?
}
@EstesE
Copy link

EstesE commented Dec 9, 2016

👍

@poteto
Copy link
Collaborator

poteto commented Dec 9, 2016

This is currently a bug that I'm going to fix - when it lands, it should be:

{
  title: validatePresence(true),
  'contactNumber.number': validatePresence(true)
}

Tracking the work here - adopted-ember-addons/ember-changeset#140

@dpigera
Copy link

dpigera commented Dec 9, 2016

@poteto We ran into this exact same problem this morning! :-) Excited for your update!

@BillyRayPreachersSon
Copy link

BillyRayPreachersSon commented Nov 13, 2017

Is there any update on when a fix for this might land?

I tried working around it by getting my top-level validator to return an object with keys containing the nested errors, but that then changes the error structure to be non-standard, and so I'd rather avoid doing that if possible.

@nucleartide
Copy link
Contributor

Hey @BillyRayPreachersSon, I'll be reviewing this sometime this week – see adopted-ember-addons/ember-changeset#140 (comment). It's high on my todo list.

@nucleartide
Copy link
Contributor

nucleartide commented Nov 14, 2017

Will have time for this on Thursday and Friday.

@erichaus
Copy link

erichaus commented Nov 19, 2017

Hola, I just ran into this exact issue and coincidence you guys are talking about it...

import CreditCardValidations from '.../validations/credit-card';
import { inject as service } from '@ember/service';

export default Component.extend(CreditCardValidations, {
    model: {
        address: {
            address_line1: null,
            address_line2: null,
            city: null,
            country: null,
            phone_number: null,
            postal_code: null,
            state_province: null
        },
        cc: {
            ccv: null,
            expiration_month: null,
            expiration_year: null,
            number: null
        },
        name: {
            first_name: null,
            last_name: null
        }
    },

This doesn't work so far...

import {
    validatePresence
} from 'ember-changeset-validations/validators';

export default {
    'name.first_name': [
        validatePresence(true)
    ],
};

@kpfefferle
Copy link

kpfefferle commented May 26, 2020

Was this issue fixed by the 3.0 release? I'm trying to validate a nested key as follows, and it does not appear to be working at this time (the other non-nested validations on this model work as expected):

// Data structure
{
  amount: {
    value: 0,
    currency: 'USD'
  }
}
// Validations
import {
  validateNumber,
  validatePresence,
} from 'ember-changeset-validations/validators';

export default {
  'amount.value': [
    validatePresence(true),
    validateNumber({ integer: true }),
  ]
};

@snewcomer
Copy link
Collaborator

@kpfefferle Prior to the 3.0 release, there were some hard to deal with bugs relating to nested keys. This was mainly due to dot separated keys. With 3.0 (and specifically 3.4.0), we have finally reached a solid solution for allowing users to retrieve CHANGES/CONTENT and set at any level in the object tree. One consequence of this is that we deal with JS objects as they are (in "expanded" form). So this should work!

export default {
  amount: {
    value: [
      validatePresence(true),
      validateNumber({ integer: true }),
    ]
  }
};

adopted-ember-addons/validated-changeset#45

@kpfefferle
Copy link

@snewcomer Great, I actually like that syntax better. I'll give that a try, thanks!

@kpfefferle
Copy link

The validation seems to be working as described, but I'm seeing the top-level object get replaced with only the nested properties from the changeset rather than preserving any properties that have not been edited.

To build on my example above, I have the following data structure:

{
  amount: {
    value: 0,
    currency: 'USD'
  }
}

I then have a changeset validating amount.value (which is editable via a form field):

// Validations
export default {
  amount: {
    value': [
      validatePresence(true),
      validateNumber({ integer: true }),
    ]
  }
};

When I apply the changeset to the underlying model, I lose the amount.currency (which was not modified by the changeset. Instead, I just get the amount.value property from the changeset:

{
  amount: {
    value: '1000'
    // currency: 'USD' has been wiped out by the changeset
  }
}

I would expect the changeset to only update amount.value here and leave amount.currency untouched.

If this should be filed as a new issue or on a different repo, please let me know.

@snewcomer
Copy link
Collaborator

Just as a quick check, what version are you on?

@kpfefferle
Copy link

@snewcomer I just updated this morning to [email protected] (which did fix a previous issue from 3.4.0!)

@snewcomer
Copy link
Collaborator

You used the never ever never value key in an object ;). Just kidding. A Change instance has a value key and that is what we were checking (obj.value). However, we should just check obj instanceof Change. Thanks for the issue and lmk if it works or not!

@kpfefferle
Copy link

@snewcomer With 3.5.1, I'm still getting my amount object squashed. I end up with something that looks like:

{
  amount: {
    value: {
      value: '1000' // nested value.value
    }
    // currency: 'USD' is still wiped out
  }
}

where I'd hope to see

{
  amount: {
    value: '1000',
    currency: 'USD'
  }
}

@snewcomer
Copy link
Collaborator

@kpfefferle With the latest e-c-v (3.5.2), is it still failing? How different is your case from this test case?

https://github.com/validated-changeset/validated-changeset/blob/e1dd9a65d19fd1e269b48049855421d32a041cfd/test/index.test.ts#L1431

@tmthn
Copy link

tmthn commented Jul 14, 2020

Might still not work with Ember Data Models. I defined a model with an attribute which contains an object:

import Model, { attr } from '@ember-data/model';

export default class TermModel extends Model {
  @attr('string') title;
  @attr({
    defaultValue() {
      return {};
    }
  }) content;
}

And created a corresponding validator with a rule for the nested object:

import {
  validatePresence
} from 'ember-changeset-validations/validators';

export default {
  title: validatePresence(true),
  content: {
    address: validatePresence(true)
  }
};

Finally in my template I followed the suggested implementation:

<div>
  Title:<br>
  <Input @value={{@changeset.title}} />
</div>

<div>
  Address:<br>
  <Input @value={{@changeset.content.address}} />
</div>

<button {{on 'click' (fn @submit @changeset)}}>
  Save
</button>

If I call the validation method, only the first level of attributes is recognized. I also tried it with a pure Javascript object and unfortunately I got the same result.

@kpfefferle
Copy link

@snewcomer Sorry for the delay on this, but I recently refactored away from the pattern that was requiring me to validate nested keys. Thanks for your responsiveness, and hopefully someone else running into the same issue can help out moving forward.

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