Aurelia绑定-点击按钮返回查看模型

Aurelia binding - back to view model on button click

本文关键字:模型 返回 按钮 绑定 -点 Aurelia      更新时间:2023-09-26

在Aurelia应用程序中,我有一个带有单个输入的"重命名"表单

<input ... value.bind="something.name" />

以及两个按钮:CCD_ 1和CCD_。

相同的something对象已在其他控件中使用。因此,在单击Save按钮之前,我不希望name发生更改。

有没有一种很好的声明性方法来实现这一点,或者我必须将name复制到另一个属性,然后在Save触发器上将其复制回来?

您可以为编辑弹出窗口创建一个模型对象,并且仅在单击Save时复制对列表中项目所做的编辑。下面是一个简化的示例:https://gist.run/?id=af3af031c5acc4c46407679f5ab1376b

查看

<template>
  <ul>
    <li repeat.for="person of people">${person.firstName} ${person.lastName} <button click.delegate="editPerson(person)">Edit</button></li>
  </ul>
  <div if.bind="editing">
    First Name: <input type="name" value.bind="editModel.firstName" />
    Last Name: <input type="name" value.bind="editModel.lastName" />
    <button click.delegate="savePerson()">Save</button>
    <button click.delegate="cancelEdit()">Cancel</button>
  </div>
</template>

ViewModel

export class App {
  editing = false;
  people = [
    { firstName: 'John', lastName: 'Doe' },
    { firstName: 'Jane', lastName: 'Smith' },
    { firstName: 'Bob', lastName: 'Smith' }
  ];
    editPerson(person) {
      this.editing = true;
      this.editObject = person;
      this.editModel = Object.assign({},person);
    }
    savePerson() {
      this.editing = false;
      Object.assign(this.editObject, this.editModel);
      this.editObject = null;
      this.editModel = null;
    }
    cancelEdit() {
      this.personBeingEdited = null;
      this.editing = false;
    }
}

我认为Ashley Grant的回答是一种非常清晰/直接的方法。我会选择这样的东西。既然您要求使用另一种方法,即使用更少的代码,那么就这样吧。。。。不确定它是否更好,这只是另一种方法,可能不太清楚。。。

https://gist.run?id=e931202307361d472c3e0ee4f523a833

视图模型具有一个名为editPerson的属性,该属性表示当前正在编辑的人员。

app.js

export class App {
  people = [
    { firstName: 'John', lastName: 'Doe' },
    { firstName: 'Jane', lastName: 'Smith' },
    { firstName: 'Bob', lastName: 'Smith' }
  ];
  editPerson = null;
  save() {
    this.editPerson.firstName = this.firstNameInput.value;
    this.editPerson.lastName = this.lastNameInput.value;
    this.editPerson = null;
  }
}

视图使用Save0绑定将视图模型数据推送到输入中。对输入的编辑不会更新模型,因为绑定是单向的。提交表单时,将调用视图模型的save()方法,该方法具有将输入值复制到模型中的逻辑。

app.html

<template>
  <ul>
    <li repeat.for="person of people">
      ${person.firstName} ${person.lastName}
      <button click.delegate="editPerson = person">Edit</button>
    </li>
  </ul>
  <form if.bind="editPerson" submit.delegate="save()">
    <label>
      First Name:
      <input ref="firstNameInput" value.one-way="editPerson.firstName">
    </label>
    <label>
      Last Name:
      <input ref="lastNameInput" value.one-way="editPerson.lastName">
    </label>
    <button type="submit">Save</button>
    <button type="button" click.delegate="editPerson = null">Cancel</button>
  </form>
</template>

这里有一个使用自定义"可取消"绑定行为的替代方案。绑定会做以下事情:

  1. 拦截updateSource以将写入重定向到隐藏存储
  2. 侦听保存事件以将隐藏的存储写回原始源

"2"是通过遵守绑定上下文上的saved属性的约定完成的。如果需要更大的灵活性,可以将属性名称作为参数传递给自定义绑定。

app.html

<template>
  <require from='./cancellable'></require>
  <div>
    Name: ${name}
    Age: ${age}
    <button click.delegate="edit()">Edit</button>
  </div>
  <div if.bind="editing">
    <h3>Cancellable edit</h3>
    Name: <input value.bind="name & cancellable">
    Age: <input value.bind="age & cancellable">
    <div><button click.delegate="save()">Save</button>
    <button click.delegate="cancel()">Cancel</button></div>
  </div>
  <div if.bind="editing">
    <h3>Instant edit</h3>
    Name: <input value.bind="name">
    Age: <input value.bind="age">
  </div>
</template>

app.js

export class App {
  constructor() {
    this.name = 'John';
    this.age = 20;
    this.editing = false;
    this.saved = false;
  }

  edit() {
    this.saved = false;
    this.editing = true;
  }
  save() {
    this.saved = true;
    this.editing = false;
  }
  cancel() {
    this.saved = false;
    this.editing = false;
  }
}

可取消.js

import {inject} from 'aurelia-dependency-injection';
import {BindingEngine} from 'aurelia-binding';
@inject(BindingEngine)
export class CancellableBindingBehavior {
  constructor(bindingEngine) {
    this.bindingEngine = bindingEngine;
  }
  bind(binding, scope) {
    let value;    
    let modified = false;
    let cancellable = {
      originalUpdateSource: binding.updateSource,
      originalUpdateTarget: binding.updateTarget,
    };
    // 1. Intercept "updateSource" to redirect write to a hidden value storage
    binding.updateSource = (val) => {
      value = val;
      modified = true;
    };
    // 2. Intercept updateTarget" so that can observe change from original source 
    binding.updateTarget = (val) => {
      value = val;
      modified = false;
      cancellable.originalUpdateTarget.call(binding, val);
    }
    // 3. Observe the "saved" event to copy back to original source 
    let bindingContext = scope.bindingContext;
    cancellable.subscription = this.bindingEngine.propertyObserver(bindingContext, 'saved')
      .subscribe((newValue, oldValue) => {
        if (newValue && modified) {
          cancellable.originalUpdateSource.call(binding, value);
        }
      });
    binding.cancellable = cancellable;
  }
  unbind(binding, scope) {
    binding.updateSource = binding.cancellable.originalUpdateSource;
    binding.updateTarget = binding.cancellable.originalUpdateTarget;
    binding.cancellable.subscription.dispose();
    binding.cancellable = null;
  }
}

Gist运行:https://gist.run/?id=2c7e40e88d1d3c18e9d2bca6be438b47

参考:内置的油门绑定行为

我所做的是制作一个我想要编辑的对象的副本,然后将其绑定到视图,当我单击保存时,我会将编辑的对象与我的原始对象"合并",以便将更改反映在其他控件中。

所以我编辑的ViewModel看起来是这样的:

activate(existingUser: User) {
    let userCopy: User = JSON.parse(JSON.stringify(existingUser));
}

在我看来,然后我使用userCopy对象来绑定属性。当我点击保存时,我会执行以下操作:

let indexOfUser = this.users.indexOf(existingUser);
Object.assign(this.users[indexOfUser], userCopy);

我简化了一些代码,因为在我的用例中,我使用的是一个对话框,该对话框将editedUser返回到不同的ViewModel,而ViewModel保存用户列表等。