如何在每次表单数据更改时更新表单相关(数据)模型?

问题描述 投票:0回答:2

我有以下函数,以便更新四个不同输入字段的值:

已更新

我的包类定义如下:

class Package {
  constructor(packageID, type, weight, height, description) {
    this.packageID = packageID;
    this.type = type;
    this.weight = weight;
    this.height = height;
    this.description = description;
  }
  getPackageId() {
    return this.packageId;
  }
  getType() {
    return this.type;
  }
  getWeight() {
    return this.weight;
  }
  getHeight() {
    return this.height;
  }
  getDescription() {
    return this.description;
  }/*
  setPackageId(packageId){
    this.packageId= packageId
    return packageId;
  }*/
  setType(type) {
    this.type = type;
    return type;
  }
  setWeight(weight) {
    this.weight = weight;
    return this.weight;
  }
  setHeight(height) {
    this.height = height;
    return this.height;
  }
  setDescription(description) {
    this.description = description;
    return this.description;
  }
}
let inputfieldtype = document.getElementById('selectPackageType');
let inputfieldweight = document.getElementById('floatWeight');
let inputfieldheight = document.getElementById('floatHeight');
let inputfielddescription = document.getElementById('description');

function updateValues() {
  var value = this.value;

  if (value == null) {

    console.log('value of packege is null');

  } else if (value != "" && (inputfieldtype == 'selectPackageType')) {
    type = value;
  } else if (value != "" && (inputfieldweight == 'floatWeight')) {
    weight = value;
  } else if (value != "" && (inputfieldheight == 'floatHeight')) {
    height = value;
  } else if (value != "" && (inputfielddescription == 'description')) {
    description = value;
  }
}
inputfieldweight.addEventListener('change', updateValues);
inputfieldheight.addEventListener('change', updateValues);
inputfielddescription.addEventListener('change', updateValues);
inputfieldtype.addEventListener('change', updateValues);

到目前为止我了解到的是,我的 if 语句的条件没有用,因为在所有四种情况下,我想要与之比较的字符串都是 true。 我的目标如下:我想检查哪个输入字段已被单击,并且我想将该字段的值保存到变量中。

然后我想创建我的类“Package”的一个新实例,并用这个值填充它们的属性。

//Create instance of package
const package = new Package();

//shoot all the values into one package
function submit() {
  if (typeof package != "undefined") {
    package.packageID = randomID;
    package.type = type;
    package.weight = weight;
    package.height = height;
    package.description = description;
    console.log(package);
  } else {
    console.log(package);
  }
}

这是 HTML 代码

<form autocomplete="off">
  <div class="custom-select">
    <label for="selectPackageType">Type</label>
    <select id="selectPackageType" name="type">
      <option value="1">letter</option>
      <option value="2">package</option>
    </select>
  </div>
</form>
<div class="fancy-input">
  <label for="floatWeight">Weight</label>
  <input id="floatWeight" name="floatWeight" maxlength="8">
</div>
<div class="fancy-input">
  <label for="floatHeight">Height</label>
  <input id="floatHeight" name="floatHeight" maxlength="8">
</div>
<div class="fancy-input">
  <label for="description">Description</label>
  <input id="description" name="description">
</div>
<button onclick="submit()">Submit</button>
javascript oop event-handling components event-delegation
2个回答
0
投票

我将代码更改为以下内容:

/**
 * this class describes the package that should be send or collect
 */

 
 class Package{
     
     constructor(packageID, type, weight,height,description){
     this.packageID = packageID;
     this.type = type;
     this.weight = weight;
     this.height = height;
     this.description= description;
     
     }
     
     getPackageId(){
         
         return this.packageId;
     }
     
     getType(){
         return this.type;
     }
     
     getWeight(){
         return this.weight;
     }
     getHeight(){
         return this.height;
     }
     getDescription(){
         return this.description;
     }
     
     /*setPackageId(packageId){
         this.packageId= packageId
         return packageId;
     }*/
     
     setType(type){
         this.type = type;
         return type;
     }
    
     
     setWeight(weight){
         
         this.weight = weight;
         return this.weight;
     }
     setHeight(height){
         this.height = height;
         return this.height;
     }
     setDescription(description){
         this.description = description;
         return this.description;
     }
     
    
}

//Generate PackageId 
const generateID = () => Math.random().toString(36).slice(2);
//Global Variables
const randomID = generateID();

const formgetInputfields = document.getElementById("getInputfields");
const inputfieldtype = document.getElementById('selectPackageType');
const inputfieldweight = document.getElementById('floatWeight');
const inputfieldheight = document.getElementById('floatHeight');
const inputfielddescription = document.getElementById('description');

//Create instance of package
const package = new Package();
//shoot all the values into one package
function submit(){  
const type = inputfieldtype.value;
const weight = inputfieldweight.value;
const height = inputfieldheight.value;
const description = inputfielddescription.value;
    console.log(formgetInputfields);
    
  if (typeof package != "undefined") {
      package.packageID = randomID;
      package.type = type;
      package.weight = weight; 
      package.height = height;
      package.description = description;   
      console.log(package);
  }else {
        console.log(package);
  }
}
formgetInputfields.addEventListener("change", submit);

看起来有效。


0
投票

为了易于维护/重构,解决方案应该实现通用且具有更高的抽象。

对于OP的用例,首先必须稍微重构表单标记,包括表单元素名称和

Package
类属性名称的统一。

说到后者,OP 的

Package
类实现引入了 getter 和 setter 方法,这些方法没有任何用途,因为 a) 无论如何,所有属性都是公共的,但 b) 也没有引入任何对 setter 实现的保护。获取/设置仅对受保护的数据有意义,因此是私有数据,人们可以控制如何允许访问甚至更改此类数据。 OP 最好使用最简单的
Package
抽象,仅包含公共数据。

包实例的创建应该始终与其形式相关。为了建立这样的关系,可以使用

WeakMap
实例,其中包配置表单元素作为其包实例的键,而后者必须根据任何表单元素进行更新其相关表单元素的值变化。

可以引入两个函数,

putPackageData
创建并注册表单相关的包实例,
patchPackageData
从表单的当前元素值创建数据补丁并将其分配给表单相关的包 -实例。

人们必须利用例如...

下一个提供的示例代码显示了刚刚描述的方法的可能实现,因为该方法是通用的,每次单个表单元素值更改或表单必须处理时,都会用所有当前可用的表单数据修补包提交事件。

function patchPackageData(evt) {
  // - prevent the form from being submitted ...
  // - but only in case a real event with its own `preventDefault` method was provided.
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault]
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining]
  evt.preventDefault?.();

  const { currentTarget: formNode } = evt;

  // - create a form-data instance.
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/API/FormData]
  const formData = new FormData(formNode);

  // - create an object from all form-data entries.
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/API/FormData/entries]
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries]
  const dataPatch = Object.fromEntries([...formData.entries()]);

  // - get the form-element related package instance.
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/get]
  const package = packageRegistry.get(formNode);

  // - assign the data-patch to the package instance.
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign]
  Object.assign(package, dataPatch);

  console.log('PATCH package data ...', package);
}
function putPackageData(formNode) {
  // - create and register the form-element related package instance.
  // - see ... [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/set]
  packageRegistry.set(
    formNode, new Package({ id: formNode.dataset.packageId }),
  );
  console.log('PUT package data ...', packageRegistry.get(formNode));

  // - assign more form-element related data to the newly created package instance.
  patchPackageData({ currentTarget: formNode });
}
const packageRegistry = new WeakMap;

document
  // - query every available package configuration related form element ...
  .querySelectorAll('form[data-name="package-config"]')

  // - ... where one for each form-element ...
  .forEach(elmNode => {

    // ... does trigger the creation and registration of the form-element related package instance.
    putPackageData(elmNode);

    // ... does register the correct handlers with the relevant event-types.
    elmNode.addEventListener('change', patchPackageData);
    elmNode.addEventListener('submit', patchPackageData);
  });
body { margin: 0; }
form {

  float: left;
  width: 25%;
  padding: 8px;
  font-size: .8em;

  label,
  label > span {

    display: block;
    width: 100%;
  }
  label > span {
    margin: 2px 0;
  }
  label, fieldset, [type="submit"] {
    margin: 4px 0;
  }
  select, input {
    width: 90%;
  }
}
.as-console-wrapper {
  left: auto!important;
  bottom: 0;
  width: 44%;
  min-height: 100%;
}
<form data-name="package-config" data-package-id="6dfc38b8-41f0-4b4f-86d8-4aea355aef79" autocomplete="off">

  <label>
    <span>Type</span>

    <select name ="type">
      <option value="1">letter</option>
      <option value="2">package</option> 
    </select>
  </label>

  <fieldset>
    <legend>Measures</legend>

    <label>
      <span>Weight</span>

      <input name="weight" maxlength="8" />
    </label>
    <label>
      <span>Height</span>

      <input name="height" maxlength ="8" />
    </label>
  </fieldset>

  <label>
    <span>Description</span>

    <input name="description" />
  </label>

  <button type="submit">Submit</button>
</form>


<form data-name="package-config" autocomplete="off">

  <label>
    <span>Type</span>

    <select name ="type">
      <option value="1">letter</option>
      <option value="2" selected>package</option> 
    </select>
  </label>

  <fieldset>
    <legend>Measures</legend>

    <label>
      <span>Weight</span>

      <input name="weight" maxlength="8" />
    </label>
    <label>
      <span>Height</span>

      <input name="height" maxlength ="8" />
    </label>
  </fieldset>

  <label>
    <span>Description</span>

    <input name="description" />
  </label>

  <button type="submit">Submit</button>
</form>


<script>
const isStringValue = value => (typeof value === 'string');
const isNonEmptyStringValue = value => (isStringValue(value) && !!value.trim());

class Package {
  // #data = {};

  constructor(options) {
    const { id, type, weight, height, description } = options;

    // Object.assign(this.#data, {
    Object.assign(this, {

      id: isNonEmptyStringValue(id) && id || crypto.randomUUID(),
      type: isNonEmptyStringValue(type) && type || 'not configured',
      weight: isNonEmptyStringValue(weight) && weight || 'not provided',
      height: isNonEmptyStringValue(height) && height || 'not provided',
      description: isNonEmptyStringValue(description) && description || 'not provided',
    });
  }/*

  get id() {
    return this.#data.id;
  }

  get type() {
    return this.#data.type;
  }
  get weight() {
    return this.#data.weight;
  }
  get height() {
    return this.#data.height;
  }
  get description() {
    return this.#data.description;
  }

  set type(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.type = value;
    }
    return this.#data.type;
  }
  set weight(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.weight = value;
    }
    return this.#data.weight;
  }
  set height(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.height = value;
    }
    return this.#data.height;
  }
  set description(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.description = value;
    }
    return this.#data.description;
  }

  valueOf() {
    return this.#data;
  }
  toString() {
    return JSON.stringify(this.valueOf());
  }
  [Symbol.toPrimitive](hint) {
    return (hint === 'string') && this.toString() || this.valueOf();
  }*/
}
</script>

编辑/更新

上述解决方案可以更改为在初始化时创建包实例的解决方案(就像它已经做的那样),但根据最近的表单元素值更改有选择地更新包数据。

对于这种情况,通过真正的 getter/setter 功能来保护数据的

Package
类实现确实有意义。

function patchPackageData(evt) {
  const { target: formControl, currentTarget: formNode } = evt;

  const package = packageRegistry.get(formNode);
  let { name: key, value } = formControl;

  value = value.trim();

  if (!!value) {
    // update.
    package[key] = value;
  }
  // bidirectional update.
  formControl.value = package[key];

  console.log('PATCH package data ...', { id: package.id, key, value: package[key] });
}

function postPackageData(formNode) {

  const formData = new FormData(formNode);
  const dataPatch = Object.fromEntries([...formData.entries()]);

  const package = packageRegistry.get(formNode);

  // post/update.
  Object.assign(package, dataPatch);

  Object
    .keys(dataPatch)

    // bidirectional update.
    .forEach(key => formNode.elements[key].value = package[key]);

  console.log('POST package data ...', package.valueOf());
}
function putPackageData(formNode) {
  packageRegistry.set(
    formNode, new Package({ id: formNode.dataset.packageId }),
  );
  console.log('PUT package data ...', packageRegistry.get(formNode).valueOf());

  postPackageData(formNode);
}
const packageRegistry = new WeakMap;

document
  .querySelectorAll('form[data-name="package-config"]')
  .forEach(elmNode => {

    putPackageData(elmNode);

    elmNode.addEventListener('change', patchPackageData);
    elmNode.addEventListener('submit', evt => evt.preventDefault());
  });
body { margin: 0; }
form {

  float: left;
  width: 25%;
  padding: 8px;
  font-size: .8em;

  label,
  label > span {

    display: block;
    width: 100%;
  }
  label > span {
    margin: 2px 0;
  }
  label, fieldset, [type="submit"] {
    margin: 4px 0;
  }
  select, input {
    width: 90%;
  }
}
.as-console-wrapper {
  left: auto!important;
  bottom: 0;
  width: 44%;
  min-height: 100%;
}
<form data-name="package-config" data-package-id="6dfc38b8-41f0-4b4f-86d8-4aea355aef79" autocomplete="off">

  <label>
    <span>Type</span>

    <select name ="type">
      <option value="1">letter</option>
      <option value="2">package</option> 
    </select>
  </label>

  <fieldset>
    <legend>Measures</legend>

    <label>
      <span>Weight</span>

      <input name="weight" maxlength="8" value="20" />
    </label>
    <label>
      <span>Height</span>

      <input name="height" maxlength ="8" />
    </label>
  </fieldset>

  <label>
    <span>Description</span>

    <input name="description" value="letter 20/3" />
  </label>

  <button type="submit">Submit</button>
</form>


<form data-name="package-config" autocomplete="off">

  <label>
    <span>Type</span>

    <select name ="type">
      <option value="1">letter</option>
      <option value="2" selected>package</option> 
    </select>
  </label>

  <fieldset>
    <legend>Measures</legend>

    <label>
      <span>Weight</span>

      <input name="weight" maxlength="8" />
    </label>
    <label>
      <span>Height</span>

      <input name="height" maxlength ="8" value="5" />
    </label>
  </fieldset>

  <label>
    <span>Description</span>

    <input name="description" />
  </label>

  <button type="submit">Submit</button>
</form>


<script>
const isStringValue = value => (typeof value === 'string');
const isNonEmptyStringValue = value => (isStringValue(value) && !!value.trim());

class Package {
  #data = {};

  constructor(options) {
    const { id, type, weight, height, description } = options;

    Object.assign(this.#data, {

      id: isNonEmptyStringValue(id) && id || crypto.randomUUID(),
      type: isNonEmptyStringValue(type) && type || 'not configured',
      weight: isNonEmptyStringValue(weight) && weight || 'not provided',
      height: isNonEmptyStringValue(height) && height || 'not provided',
      description: isNonEmptyStringValue(description) && description || 'not provided',
    });
  }

  get id() {
    return this.#data.id;
  }

  get type() {
    return this.#data.type;
  }
  get weight() {
    return this.#data.weight;
  }
  get height() {
    return this.#data.height;
  }
  get description() {
    return this.#data.description;
  }

  set type(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.type = value;
    }
    return this.#data.type;
  }
  set weight(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.weight = value;
    }
    return this.#data.weight;
  }
  set height(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.height = value;
    }
    return this.#data.height;
  }
  set description(value) {
    if (isNonEmptyStringValue(value)) {

      this.#data.description = value;
    }
    return this.#data.description;
  }

  valueOf() {
    return this.#data;
  }
  toString() {
    return JSON.stringify(this.valueOf());
  }
  [Symbol.toPrimitive](hint) {
    return (hint === 'string') && this.toString() || this.valueOf();
  }
}
</script>

© www.soinside.com 2019 - 2024. All rights reserved.