Skip to content

Commit 5cbc712

Browse files
committed
feat: Resolve 149, new method acceptChanges, test for acceptChanges.
1 parent d4d5977 commit 5cbc712

File tree

6 files changed

+156
-18
lines changed

6 files changed

+156
-18
lines changed

src/classes/Form.ts

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import isPrefixName from "../utils/is-prefix-name";
2222
import findNearestNameFromArray from "../utils/find-nearest-name-from-array";
2323
import findNearestPrefixFromArray from "../utils/find-nearest-prefix-from-array";
2424
import AvailabilityEvent from "./AvailabilityEvent";
25+
import plainObject from "../utils/plain-object";
26+
import bypassObject from "../utils/bypass-object";
2527

2628
/**
2729
* Main principe : GMN
@@ -180,7 +182,11 @@ export default class Form extends EventEmitter implements FormDependence {
180182
// По options функция возвращает ссылку на объект, которые изменяется
181183
function getTargetValue(this: Form) {
182184
const fieldName = concatName(options.executedFrom, options.target);
183-
185+
186+
/**
187+
* @description Это неверный подход. Он чётче может сказать что изменилось, но точно не правильнее.
188+
* Предыдущее значение всегда должно браться только из values.
189+
* */
184190
// Если имеется change и clean - то мы не работаем с values, т.к. к нему примешены другие changes.
185191
//const values = (options.change && options.clean) ? this.pureValues : this.values;
186192

@@ -194,13 +200,17 @@ export default class Form extends EventEmitter implements FormDependence {
194200
debug.msg('%cTarget Values:', debug.colorFocus, targetValues)
195201

196202
// Если параметр clean, был передан, мы используем функцию полного сравнения, а не сравнения изменений.
203+
// Сливаем ExecutedFrom Target Name
197204
const compareResult = (options.clean ? compareDifference : compareMergeChanges)(targetValues, grandValues)
198205
.map(item => {
199206
item.name = concatName(options.executedFrom, options.target, item.name);
200207
return item;
201208
})
202-
203-
// Пока используется для того, чтобы добавить CompareResult для executedFrom и target
209+
210+
/**
211+
* @description Т.к.есть механизм executedBy и target мы к compareResult должны добавить родительские изменения,
212+
* которые автоматически затрагиваются при изменении дочерних.
213+
* */
204214
function superCompare(this: Form, compareResult: CompareItem[], superName: string): CompareItem[] {
205215
const copy = copyObject(this.values);
206216
compareResult.forEach(data => {
@@ -227,7 +237,6 @@ export default class Form extends EventEmitter implements FormDependence {
227237

228238
debug.msg('Result', test);
229239
debug.groupEnd();
230-
231240
}
232241

233242

@@ -238,7 +247,23 @@ export default class Form extends EventEmitter implements FormDependence {
238247
// В случае, когда change: false, изменения затрагивают как this.values, так и удаление полей из this.changes.
239248
// Т.к. туда передаётся CompareItem[], то все изменения уже просчитаны и нам нужно их просто спроецировать на объект.
240249
this.mergeValues(compareResult, options.change);
241-
250+
251+
/**
252+
* @description Если текущий процесс не является changed - мы проходим по конечным точкам значений и проверяем:
253+
* Если поле до сих пор находится в статусе change -> мы должны подтвердить данное изменение и переместить их на
254+
* pureValues.
255+
* */
256+
if (!options.change) {
257+
const extendName = concatName(options.executedFrom, options.target)
258+
const extendValues = extendName ? {[extendName]: values} : values
259+
const keys = Object.keys(plainObject(extendValues));
260+
261+
keys.forEach(endPointName => {
262+
if (this.checkFieldChange(endPointName))
263+
this.acceptChanges(endPointName)
264+
});
265+
}
266+
242267
// После того как изменения были спроецированы на формы, происходит создание события и уведомления всех дочерних
243268
// и выполнения внешних событий.
244269

@@ -251,8 +276,30 @@ export default class Form extends EventEmitter implements FormDependence {
251276
debug.groupEnd();
252277

253278
debug.groupEnd();
254-
255-
279+
}
280+
/**
281+
* @description Метод для принятия изменения и переноса их в pureValues
282+
* */
283+
acceptChanges(name?: string) {
284+
if (name) {
285+
286+
if (!checkNameInObject(this.changes, name)) {
287+
debug.msg(`%cCan't accept%c changes for %c${name}%c, field not founded in changes.`,
288+
debug.colorError, debug.colorDefault, debug.colorName, debug.colorDefault)
289+
return;
290+
}
291+
292+
293+
debug.msg(`%caccept%c changes for ${name}`, debug.colorSuccess, debug.colorDefault)
294+
const values = getPropFromObject(this.changes, name);
295+
296+
recursiveRemoveProp(this.#changes, name);
297+
insertByName(this.#values, name, values);
298+
} else {
299+
mergeObjects(this.#values, this.#changes);
300+
this.#changes = {};
301+
}
302+
256303
}
257304

258305
/**
@@ -289,7 +336,7 @@ export default class Form extends EventEmitter implements FormDependence {
289336
}))
290337
}
291338

292-
// Если при изменении новое значение совпадает со значением, находящимся в pureValues. Это означает, что
339+
// Если при изменении новое значение совпадает со значением, находящимся в pureValues. Это означает, то
293340
// Что новое значение эквивалентно значению по умолчанию.
294341
// В таком случае рекурсивно чистим значение
295342
if (isChange && isEndPointValue(item.newValue) && item.newValue === getPropFromObject(this.pureValues, item.name)) {
@@ -311,8 +358,8 @@ export default class Form extends EventEmitter implements FormDependence {
311358
((isEndPointValue(item.newValue) || isEndPointValue(item.oldValue)) && !isChange)
312359
// || (item.newValue === undefined && isChange)
313360
) {
314-
debug.msg(`%cReturn%c changes for %c${item.name}%c`,
315-
debug.colorFocus, debug.colorDefault, debug.colorName, debug.colorDefault
361+
debug.msg(`%cRevert%c changes for %c${item.name}%c`,
362+
debug.colorError, debug.colorDefault, debug.colorName, debug.colorDefault
316363
);
317364
// this.cleanChangesByField(item.name);
318365
recursiveRemoveProp(this.#changes, item.name)
@@ -584,11 +631,7 @@ export default class Form extends EventEmitter implements FormDependence {
584631
* After success saving changes will be merged(overwrite) with values.
585632
* Is Bug: https://github.com/Jenesius/vue-form/issues/149
586633
* */
587-
array.push(() => {
588-
const saveChanges = copyObject(this.changes);
589-
this.revert();
590-
this.setValues(saveChanges);
591-
});
634+
array.push(this.acceptChanges.bind(this, undefined));
592635
}
593636

594637

tests/integrations/input-text.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,6 @@ describe("Input text", () => {
129129

130130
const input = app.get('input');
131131

132-
console.log(input.element.name, input.element.classList)
133-
134132
expect(input.element.disabled).toBe(true)
135133
})
136134
test("Input should remove disable class after form.enable", async () => {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import Form from "../../../src/classes/Form";
2+
3+
describe("Form accept changes", () => {
4+
test("Accept clean changes", () => {
5+
const form = new Form();
6+
form.setValues({test: 1});
7+
form.acceptChanges("address");
8+
expect(form.changes).toEqual({})
9+
expect(form.values).toEqual({test: 1})
10+
})
11+
test("Accept primitive value", () => {
12+
const form = new Form();
13+
form.setValues({test: 1});
14+
form.change({name: "Jack"});
15+
form.acceptChanges("name");
16+
expect(form.changes).toEqual({})
17+
expect(form.values).toEqual({test: 1, name: "Jack"})
18+
})
19+
test("Accept object value", () =>{
20+
const form = new Form();
21+
form.setValues({test: 1});
22+
form.change({address: {
23+
city: {
24+
index: 111
25+
}
26+
}});
27+
form.acceptChanges("address");
28+
expect(form.changes).toEqual({})
29+
expect(form.values).toEqual({test: 1, address: { city:{ index: 111 } }})
30+
})
31+
test("Accept one child of multi object", () => {
32+
const _changes = { address: { city: { index: 111 }, country: "Canada" } };
33+
const form = new Form();
34+
form.change(_changes);
35+
form.acceptChanges('address.city');
36+
expect(form.changes).toEqual({ address: {country: "Canada"} })
37+
expect(form.pureValues).toEqual({ address: { city: { index: 111 } } })
38+
})
39+
test("Accept one child of single object", () => {
40+
const _changes = { address: { city: { index: 111 }} };
41+
const form = new Form();
42+
form.change(_changes);
43+
form.acceptChanges('address.city.index');
44+
expect(form.changes).toEqual({ })
45+
expect(form.pureValues).toEqual({ address: { city: { index: 111 } } })
46+
})
47+
test("Accept multi value for primitive", () => {
48+
const form = new Form();
49+
form.change({
50+
age: 25
51+
})
52+
form.acceptChanges('age.index.code');
53+
54+
expect(form.changes).toEqual({
55+
age: 25
56+
})
57+
expect(form.pureValues).toEqual({})
58+
})
59+
test("Accept clean without name for clean changes", () =>{})
60+
test("Accept clean without name", () =>{})
61+
})

tests/units/form/form-oninput.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,29 @@ describe("Form oninput handler", () => {
193193
expect(mockChange.mock.results[0].value).toBe(undefined);
194194
expect(form.changes).toEqual({})
195195
})
196+
test("Setting the same value should not execute event", () => {
197+
const form = new Form();
198+
const mockOninput = jest.fn(x => x);
199+
form.oninput('age', mockOninput);
200+
201+
form.setValues({age: 1})
202+
form.setValues({age: 3})
203+
form.setValues({age: 3});
204+
form.setValues({age: 3});
205+
expect(mockOninput.mock.results.length).toBe(2)
206+
expect(mockOninput.mock.results[0].value).toBe(1)
207+
expect(mockOninput.mock.results[1].value).toBe(3)
208+
})
209+
test("Setting the same value after change should not execute event", () => {
210+
const form = new Form();
211+
const mockOninput = jest.fn(x => x);
212+
form.oninput('age', mockOninput);
213+
214+
form.change({age: 23})
215+
form.setValues({age: 24})
216+
217+
expect(mockOninput.mock.results.length).toBe(2)
218+
expect(mockOninput.mock.results[0].value).toBe(23)
219+
expect(mockOninput.mock.results[1].value).toBe(24)
220+
})
196221
})

tests/units/form/form-set-values.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,5 +503,17 @@ describe("Form.setValues", () => {
503503

504504
expect(form.changes).toEqual({})
505505
})
506+
test("Setting equal object using setValues after change", () => {
507+
const form = new Form()
508+
form.change({
509+
username: "Jack"
510+
})
511+
form.setValues({
512+
username: "Jack"
513+
})
514+
515+
expect(form.changes).toEqual({})
516+
expect(form.values).toEqual({ username: "Jack" })
517+
})
506518

507519
})

tests/units/form/form-validate.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ describe("Form validate", () => {
4141
name: "city",
4242
index: 0,
4343
validate() {
44-
console.log(this.index > 0)
4544

4645
return this.index++ > 0
4746
}

0 commit comments

Comments
 (0)