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

[5.x] Add parent keyword to field conditions #9385

Open
wants to merge 3 commits into
base: 5.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion resources/js/components/field-conditions/Converter.js
Expand Up @@ -32,7 +32,7 @@ export default class {
}

getScopedFieldHandle(field, prefix) {
if (field.startsWith('root.') || ! prefix) {
if (field.startsWith('root.') || field.startsWith('parent.') || ! prefix) {
return field;
}

Expand Down
23 changes: 19 additions & 4 deletions resources/js/components/field-conditions/Validator.js
Expand Up @@ -20,8 +20,9 @@ const NUMBER_SPECIFIC_COMPARISONS = [
];

export default class {
constructor(field, values, store, storeName) {
constructor(field, values, store, storeName, dottedFieldPath = '') {
this.field = field;
this.dottedFieldPath = dottedFieldPath;
this.values = values;
this.rootValues = store ? store.state.publish[storeName].values : false;
this.store = store;
Expand Down Expand Up @@ -204,9 +205,23 @@ export default class {
}

getFieldValue(field) {
return field.startsWith('root.')
? data_get(this.rootValues, field.replace(new RegExp('^root.'), ''))
: data_get(this.values, field);
if (field.startsWith('root.')) {
return data_get(this.rootValues, field.replace(new RegExp('^root.'), ''));
}

if (field.startsWith('parent.')) {
const fieldHandle = field.replace(new RegExp('^parent.'), '');
// Regex for fields like replicators, where the path ends with `parent_field_handle.0.field_handle`.
let regex = new RegExp('.[^\.]+\.[0-9]+\.[^\.]*$');
if (this.dottedFieldPath.match(regex)) {
return data_get(this.rootValues, `${this.dottedFieldPath.replace(regex, '')}.${fieldHandle}`);
}

// We dont’t have a regex field or similar, so the end of the field path looks like `parent_field_handle.field_handle`.
return data_get(this.rootValues, `${this.dottedFieldPath.replace(new RegExp('.[^\.]+\.[^\.]*$'), '')}.${fieldHandle}`);
}

return data_get(this.values, field);
}

passesCondition(condition) {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/field-conditions/ValidatorMixin.js
Expand Up @@ -25,7 +25,7 @@ export default {
}

// Use validation to determine whether field should be shown.
let validator = new Validator(field, this.values, this.$store, this.storeName);
let validator = new Validator(field, this.values, this.$store, this.storeName, dottedFieldPath);
let passes = validator.passesConditions();

// If the field is configured to always save, never omit value.
Expand Down
14 changes: 14 additions & 0 deletions resources/js/tests/FieldConditionsConverter.test.js
Expand Up @@ -49,6 +49,20 @@ test('it converts from blueprint format and does not apply prefix to root field
expect(converted).toEqual(expected);
});

test('it converts from blueprint format and does not apply prefix to parent field conditions', () => {
let converted = FieldConditionsConverter.fromBlueprint({
'name': 'isnt joe',
'parent.title': 'not empty',
}, 'nested_');

let expected = [
{field: 'nested_name', operator: 'not', value: 'joe'},
{field: 'parent.title', operator: 'not', value: 'empty'}
];

expect(converted).toEqual(expected);
});

test('it converts to blueprint format', () => {
let converted = FieldConditionsConverter.toBlueprint([
{field: 'name', operator: 'isnt', value: 'joe'},
Expand Down
13 changes: 10 additions & 3 deletions resources/js/tests/FieldConditionsValidator.test.js
Expand Up @@ -95,8 +95,8 @@ const Fields = new Vue({
}
});

let showFieldIf = function (conditions=null) {
return Fields.showField(conditions ? {'if': conditions} : {});
let showFieldIf = function (conditions=null, dottedFieldPath=null) {
return Fields.showField(conditions ? {'if': conditions} : {}, dottedFieldPath);
};

afterEach(() => {
Expand Down Expand Up @@ -322,6 +322,8 @@ test('it can run conditions on nested data', () => {
expect(showFieldIf({'address.country': 'Australia'})).toBe(false);
expect(showFieldIf({'root.user.address.country': 'Canada'})).toBe(true);
expect(showFieldIf({'root.user.address.country': 'Australia'})).toBe(false);
expect(showFieldIf({'parent.name': 'Han'}, 'user.address.country')).toBe(true);
expect(showFieldIf({'parent.name': 'Chewy'}, 'user.address.country')).toBe(false);
});

test('it can run conditions on root store values', () => {
Expand All @@ -346,13 +348,18 @@ test('it can run conditions on prefixed fields', async () => {
test('it can run conditions on nested prefixed fields', async () => {
Fields.setValues({
prefixed_first_name: 'Rincess',
prefixed_last_name: 'Pleia'
prefixed_last_name: 'Pleia',
prefixed_address: {
home_planet: 'Alderaan'
}
}, 'nested');

expect(Fields.showField({prefix: 'prefixed_', if: {first_name: 'is Rincess', last_name: 'is Pleia'}})).toBe(true);
expect(Fields.showField({prefix: 'prefixed_', if: {first_name: 'is Rincess', last_name: 'is Holo'}})).toBe(false);
expect(Fields.showField({if: {'root.nested.prefixed_last_name': 'is Pleia'}})).toBe(true);
expect(Fields.showField({if: {'root.nested.prefixed_last_name': 'is Holo'}})).toBe(false);
expect(Fields.showField({if: {'parent.prefixed_last_name': 'is Pleia'}}, 'nested.prefixed_address.home_planet')).toBe(true);
expect(Fields.showField({if: {'parent.prefixed_last_name': 'is Holo'}}, 'nested.prefixed_address.home_planet')).toBe(false);
});

test('it can call a custom function', () => {
Expand Down