How to present form parameters that depend on other forms

I have a form that is proposed to help the user select a specific thing at the end, but as the user fills in the first parameters, the rest below change. Something like that:

Type: { t1:{ Number of X:{ 1:{...} 2:{...} } Number of Y:{...} } t2:{ Number of X:{ 100:{...} 200:{...} } Number of Y:{...} } } 

The user has a Type field with parameters t1 and t2, when they select t1, the Number of X field will be filled in 1 and 2, if they choose t2, the Number of X field will be filled in 100 and 200, and so on. Some of the options depend on more than one field, its indirect dependence (something like, if the user selects "Number X" = 100, then Foo is "A", otherwise Foo can be "A", "B", or " C ", but Foo does not light up" Number X ").

I tried a really naive implementation where I would set event listeners in each field and see their changes, but in the end the code started to get out of control and I have a bunch of $("#foo").change(function(){...}); , and its unclearly obvious that the field listening is bar , not fbar .

I also tried JSON (as an example above), but there are a lot of repetitions, the deeper the tree grows, but the number of possible increases, I have to write the same fields again and again. Sometimes choosing t1 will change the parameter directly, even if it is not directly below it, and even if it usually depends on another field entirely and that there are more repetitions in JSON.

How do I approach this problem? Is there a readable solution? Too much code is not a problem if you can look at the code and understand the dependencies and their effects.

Sample code (like my code right now):

HTML:

 <select id="type"> <option value=1>a</option> <option value=2>b</option> </select> <select id="numOfX"> </select> <select id="numOfY"> </select> 

JS:

 $("#type").change(function() { if($("#type").val() == 1) { $("#numOfX").append(new Option(1, "1", false, false)); $("#numOfX").append(new Option(2, "2", false, false)); } else if($("#type").val() == 2) { $("#numOfX").append(new Option(1, "100", false, false)); $("#numOfX").append(new Option(2, "200", false, false)); } }); $("#numOfX").change(function() { ... }); 
+4
source share
2 answers

Refresh - Add Example

Try the backbone.js library? This will make Javascript more manageable by adding models and structures. However, there is a learning curve, but it is really great. After learning Backbone, you can use the Backbone Forms plugin to help you manage your drop-down list. Below is a demo link and sample code:

Example 1

 $(function() { var cities = { 'UK': ['London', 'Manchester', 'Brighton', 'Bristol'], 'USA': ['London', 'Los Angeles', 'Austin', 'New York'] }; var subAreas = { 'London' : ['L1', 'L2', 'L3', 'L4'], 'Manchester' : ['M1', 'M2', 'M3', 'M4'], 'Brighton' : ['B1', 'B2', 'B3', 'B4'], 'Bristol' : ['BR1', 'BR2', 'BR3', 'BR4'], 'Los Angeles' : ['LA1', 'LA2', 'LA3', 'LA4'], 'Austin' : ['A1', 'A2', 'A3', 'A4'], 'New York' : ['NY1', 'NY2', 'NY3', 'NY4'] }; //The form var form = new Backbone.Form({ schema: { country: { type: 'Select', options: ['UK', 'USA'] }, city: { type: 'Select', options: cities.UK }, subArea: { type: 'Select', options: subAreas[cities.UK[0] ] } } }).render(); form.on('country:change', function(form, countryEditor) { var country = countryEditor.getValue(), newOptions = cities[country]; form.fields.city.editor.setOptions(newOptions); var city = newOptions[0], areaOptions = subAreas[city]; form.fields.subArea.editor.setOptions(areaOptions); }); form.on('city:change', function(form, cityEditor) { var city = cityEditor.getValue(), newOptions = subAreas[city]; form.fields.subArea.editor.setOptions(newOptions); }); //Add it to the page $('body').append(form.el); 

});

Example 2

 $(function() { var cities = { 'UK': ['London', 'Manchester', 'Brighton', 'Bristol'], 'USA': ['London', 'Los Angeles', 'Austin', 'New York'] }; var subAreas = { 'UK.London' : ['L1', 'L2'], 'USA.London' : ['L3', 'L4'], 'UK.Manchester' : ['M1', 'M2', 'M3', 'M4'], 'UK.Brighton' : ['B1', 'B2', 'B3', 'B4'], 'UK.Bristol' : ['BR1', 'BR2', 'BR3', 'BR4'], 'USA.Los Angeles' : ['LA1', 'LA2', 'LA3', 'LA4'], 'USA.Austin' : ['A1', 'A2', 'A3', 'A4'], 'USA.New York' : ['NY1', 'NY2', 'NY3', 'NY4'] }; var hashFunc = function(country, city){ return country + "." + city; }; //The form var form = new Backbone.Form({ schema: { country: { type: 'Select', options: ['UK', 'USA'] }, city: { type: 'Select', options: cities.UK }, subArea: { type: 'Select', options: subAreas[ 'UK.London' ] } } }).render(); form.on('country:change', function(form, countryEditor) { var country = countryEditor.getValue(), newOptions = cities[country]; form.fields.city.editor.setOptions(newOptions); var city = newOptions[0], areaOptions = subAreas[hashFunc(country, city) ]; form.fields.subArea.editor.setOptions(areaOptions); }); form.on('city:change', function(form, cityEditor) { var city = cityEditor.getValue(), newOptions = subAreas[hashFunc(form.getValue().country, city)]; form.fields.subArea.editor.setOptions(newOptions); }); //Add it to the page $('body').append(form.el); });​ 

As you are also developing for mobile devices (possibly Phonegap), you can also try ZeptoJS as an alternative to jQuery. This will greatly improve speed.

+1
source

The highlighted task is complicated due to dependencies, so you should think about ways to define your dependencies. Here is one way to do this:

  • Identify the models that process the data.
  • Identify the dependencies.
  • Dependency management.

Below you can see the conceptual model, as I see it all implemented (at the end of my answer I describe things that are not provided for in this pseudocode):

 //data/model structure for Type. var type = { //list all values. values: [ { id: 1, text: 't1', visible: true }, { Id: 2, text: 't2', visible: true } ], //evaluates visibility of item using dependencies. //depends on nothing, so takes no arguments except item. evaluate: function(item) { return; //depends on nothing. }, // this event fires when selected item changes. onChange: event }; //data/model structure for number of X. var numberOfX = { //list all values. values: [ { id: 1, text: '1', visible: true }, { id: 2, text: '2', visible: true }, { id: 3, text: '100', visible: true }, { id: 4, text: '200', visible: true } ], //evaluates visibility of item using dependencies. //since numberOfX depends on Type, it takes type as second argument. //it would take more arguments if it depended on other things too. evaluate: function(item, type) { // next line will fire onChange event. item.visible = ( [1,2].indexOf(item.id) >=0 && type.id == 1 ) || ( [3,4].indexOf(item.id) >=0 && type.id == 2 ); }, // this event fires when selected item changes. onChange: event }; //data/model structure for number of Y. var numberOfY = { /* omitted. This is similar to the previous ones */ } //numberOfX depends on Type. //if it depended on more objects, then we would pass them as additional arguments. register_dependency(numberOfX, type); //numberOfY depends on Type. register_dependency(numberOfY, type); //... etc: define other dependencies. 

The event mechanism is absent in JavaScript, but it is not difficult to implement it. You can also use some framework for this.

Function

register_dependency creates a dependency graph simply by registering for events, as described below ( Dependency Management ):

When the onChange event fires in any model, evaluate is called for each element in the dependency tree. For example, when type.onChange triggered, we have objects numberOfX and numberOfY . Their values array is enumerated in a loop and evaluate is called for each element (passing item and type as arguments).

Conclusion: although this code seems complicated, it is more self-describing and allows you to have a dependency graph between several objects on the page. In addition, all the complexity lies at the level of tools / frameworks that could be easily used when implemented only once.

EDIT: I forgot to indicate that you will need to have a mechanism for binding to this model and show it on the page, which is also trivial. For example, see knockout.js .

0
source

Source: https://habr.com/ru/post/1444883/


All Articles