简体   繁体   中英

Iterate over an HTMLcollection to dynamically define values in a constructor function?

i'll get right to the description and example code as i bet many of you are as confused about the title as i am (tried my best).

Situation: I have a form that submits input data to a new instance of an object, using a constructor function.

CURRENT CODE:

// Selectors
var submit = document.getElementById('submit-btn');
var formValues = document.getElementsByClassName('input');

// ** Task Object
function Task(arrayOfValues) {
  this.title = arrayOfValues[0].value;
  this.deadline = arrayOfValues[1].value;
  this.status = arrayOfValues[2].value;
}
submit.addEventListener('click', function(e) {
  e.preventDefault();
  var newTask = new Task(formValues);  
}, false);

Problem: Passing the array as an argument and assigning each index manually feels incredibly brittle to me. If i were to extend the data collection of the form i would have to manually assign each new value as a separate variable. What is the syntax or pattern if you will for iterating over an array and dynamically assigning values to variables in a constructor function ? Thank you in advance. Any and all help is much appreciated.

EXAMPLE of desired CODE

var formValues = document.getElementsByClassName('input');

// ** Task Object
function Task(arrayOfValues) {
  this.values = arrayOfValues;

  for (var i=0;i<this.values.length;i++) {
    var key = this.values[i].getAttribute('name'); 
    // This should be used with "this" to reference key ie. "this.title, this.deadline, this.status ect...

    var value = this.values[i].value;
    // This will be the value associated with each key reference ie. "this"

    return this[key] = value;
    // is this even possible ?        
  }

}
submit.addEventListener('click', function(e) {
  e.preventDefault();
  var newTask = new Task(formValues);  
}, false);

I would just take the three parameters separately, let the caller figure out which one is the title, deadline or status

function Task(title, deadline, status) {
  this.title = title;
  this.deadline = deadline;
  this.status = status;
}

Now your callers can figure out which one is which by using IDs, data-attributes, or anything they want.

<input id="title-x"> <input id="deadline"> <input id="status">

submit.addEventListener('click', function(e) {
  e.preventDefault();
  var getVal = function(id) { return  document.getElementById(id).value; }
  var newTask = new Task(getVal('title-x'), getVal('deadline'), getVal('status'));  
}, false);

Now your constructor doesn't rely on the order within the array, or even that they are DOM elements.

You could always have a contract where a specific input maps to a task field through data-attributes

<input data-task-field="title">
<input data-task-field="deadline">
<input data-task-field="status">
<input data-task-field="newField">

/**
 * @param {object} taskDescription 
 * @param {string} taskDescription.title
 * @param {string} taskDescription.deadline
 * @param {string} taskDescription.status
 * @param {string} taskDescription.newField
 */
function Task(taskDescription) {
  this.task = taskDescription;
}

submit.addEventListener('click', function(e) {
  e.preventDefault();
  var tasks = document.querySelectorAll('input[data-task-field]');
  var taskSpec = {};
  for (var i=0; i < tasks.length; i++) {
    taskSpec[tasks.getAttribute('data-task-field')] = tasks.value; 
  }
  var newTask = new Task(taskSpec);  
}, false);

Just use the names of the form elements as the property names in the object.

function Task(arrayOfValues) {
  for (var i=0;i<arrayOfValues.length;i++) {
    var key = arrayOfValues[i].name;
    var value = arrayOfValues[i].value;
    this[key] = value;       
  }
}

Don't use return inside the loop, that will end the constructor after processing the first element in the array, and ignore the rest.

I would use an associative array -

http://www.w3schools.com/js/js_arrays.asp

var assArray = [];
assArray["title"] = document.getElementbyID(......)

That makes your array semantically meaningful and less brittle. It doesn't matter if you expand the form, so long as you don't change the names it will continue to work.

It also means you don't have to change the call signature of your constructor each time you expand the form, you only have to alter the body to deal with the new elements in the array (or not, as you so choose).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM