diff --git a/packages/mask/src/index.js b/packages/mask/src/index.js index 4823d8ebd..54fb22fac 100644 --- a/packages/mask/src/index.js +++ b/packages/mask/src/index.js @@ -52,6 +52,14 @@ export default function (Alpine) { let updater = el._x_forceModelUpdate el._x_forceModelUpdate = (value) => { + // If the model value was cleared (e.g. the parent object was + // removed), just clear the input — don't format and write back + // as that would resurrect the model path with an empty value. + if (value === undefined) { + lastInputValue = '' + return updater(value) + } + value = String(value) let template = templateFn(value) if (template && template !== 'false') { diff --git a/tests/cypress/integration/plugins/mask.spec.js b/tests/cypress/integration/plugins/mask.spec.js index dc6995a64..31111d2c0 100644 --- a/tests/cypress/integration/plugins/mask.spec.js +++ b/tests/cypress/integration/plugins/mask.spec.js @@ -1,4 +1,4 @@ -import { haveData, haveValue, html, test } from '../../utils' +import { haveData, haveText, haveValue, html, test } from '../../utils' test('x-mask', [html``], @@ -293,3 +293,33 @@ test('x-mask masks programmatic x-model updates', get('div').should(haveData('value', '23,420')) } ) + +test('x-mask with x-model initializes missing object key', + [html` +
+ + +
+ `], + ({ get }) => { + get('#output').should(haveText('EXISTS:')) + get('#1').type('1234').should(haveValue('1,234')) + get('#output').should(haveText('EXISTS:1,234')) + } +) + +test('x-mask does not resurrect x-model value when model is cleared', + [html` +
+ + + +
+ `], + ({ get }) => { + get('input').should(haveValue('5,000')) + get('#output').should(haveText('EXISTS')) + get('button').click() + get('#output').should(haveText('GONE')) + } +)