Pārlūkot izejas kodu

feat: `update_input` command support update options and label

wangweimin 4 gadi atpakaļ
vecāks
revīzija
ffac6fefad

+ 5 - 2
docs/spec.rst

@@ -151,15 +151,18 @@ Update the input item, you can update the ``spec`` of the input item of the curr
 The ``spec`` fields of ``update_input`` commands:
 
 * target_name: str The name of the target input item.
-* target_value: str, optional. Used to filter options in checkbox, radio, actions type
+* target_value: str, optional. Used to filter item in checkbox, radio
 * attributes: dist, fields need to be updated
 
   * valid_status: When it is bool, it means setting the state of the input value, pass/fail; when it is 0, it means clear the valid_status flag
   * value: Set the value of the item
+  * label
   * placeholder
   * invalid_feedback
   * valid_feedback
-  * other fields of item's ``spec`` // not support to inline and label fields
+  * help_text
+  * options: only available in checkbox, radio and select type
+  * other fields of item's ``spec`` // not support the ``inline`` field
 
 
 close_session

+ 3 - 5
webiojs/src/models/input/base.ts

@@ -64,14 +64,12 @@ export class InputItem {
         let attr2selector: { [i: string]: string } = {
             'invalid_feedback': 'div.invalid-feedback',
             'valid_feedback': 'div.valid-feedback',
-            'help_text': 'small.text-muted'
+            'help_text': 'small.text-muted',
+            'label': '>label',
         };
         for (let attribute in attr2selector) {
             if (attribute in attributes) {
-                if (input_idx === -1)
-                    this.element.find(attr2selector[attribute]).text(attributes[attribute]);
-                else
-                    this.element.find(attr2selector[attribute]).eq(input_idx).text(attributes[attribute]);
+                this.element.find(attr2selector[attribute]).text(attributes[attribute]);
                 delete attributes[attribute];
             }
         }

+ 45 - 27
webiojs/src/models/input/checkbox_radio.ts

@@ -2,18 +2,22 @@ import {Session} from "../../session";
 import {InputItem} from "./base";
 import {deep_copy} from "../../utils"
 
+const options_tpl = `
+{{#options}}
+<div class="form-check {{#inline}}form-check-inline{{/inline}}">
+    <input type="{{type}}" id="{{id_name_prefix}}-{{idx}}" name="{{name}}" {{#selected}}checked{{/selected}} {{#disabled}}disabled{{/disabled}} class="form-check-input">
+    <label class="form-check-label" for="{{id_name_prefix}}-{{idx}}">
+        {{label}}
+    </label>
+</div>
+{{/options}}
+`;
+
 const checkbox_radio_tpl = `
 <div class="form-group">
     {{#label}}<label>{{label}}</label>{{/label}}
     {{#inline}}<br>{{/inline}}
-    {{#options}}
-    <div class="form-check {{#inline}}form-check-inline{{/inline}}">
-        <input type="{{type}}" id="{{id_name_prefix}}-{{idx}}" name="{{name}}" {{#selected}}checked{{/selected}} {{#disabled}}disabled{{/disabled}} class="form-check-input">
-        <label class="form-check-label" for="{{id_name_prefix}}-{{idx}}">
-            {{label}}
-        </label>
-    </div>
-    {{/options}}
+    ${options_tpl}
     <div class="invalid-feedback">{{invalid_feedback}}</div> 
     <div class="valid-feedback">{{valid_feedback}}</div>
     <small id="{{id_name}}_help" class="form-text text-muted">{{help_text}}</small>
@@ -27,34 +31,38 @@ export class CheckboxRadio extends InputItem {
     }
 
     create_element(): JQuery {
+        let spec = this.setup_spec();
+        const html = Mustache.render(checkbox_radio_tpl, spec);
+        let elem = $(html);
+        this.setup_input_options(elem, spec.options);
+        this.element = elem;
+        return this.element;
+    }
+
+    setup_spec() {
         let spec = deep_copy(this.spec);
         const id_name_prefix = spec.name + '-' + Math.floor(Math.random() * Math.floor(9999));
         spec['id_name_prefix'] = id_name_prefix;
         for (let idx in spec.options) {
             spec.options[idx]['idx'] = idx;
         }
-        const html = Mustache.render(checkbox_radio_tpl, spec);
-        let elem = $(html);
-        this.element = elem;
+        return spec;
+    }
 
+    setup_input_options(elem: JQuery, options: any) {
         let inputs = elem.find('input');
-        for (let idx = 0; idx < spec.options.length; idx++)
-            inputs.eq(idx).val(JSON.stringify(spec.options[idx].value));
-
-        const ignore_keys = {'value': '', 'label': '', 'selected': ''};
-        for (let idx = 0; idx < this.spec.options.length; idx++) {
-            let input_elem = elem.find('#' + id_name_prefix + '-' + idx);
-            // blur事件时,发送当前值到服务器
-            // checkbox_radio 不产生blur事件
-            // input_elem.on('blur', this.send_value_listener);
-
+        for (let idx = 0; idx < options.length; idx++) {
+            let input_elem = inputs.eq(idx);
+            input_elem.on("blur", (e) => {
+                this.send_value_listener(this, e);
+            });
+            input_elem.val(JSON.stringify(options[idx].value));
             // 将额外的html参数加到input标签上
-            for (let key in this.spec.options[idx]) {
-                if (key in ignore_keys) continue;
-                input_elem.attr(key, this.spec.options[idx][key]);
+            for (let key in options[idx]) {
+                if (key in {'value': '', 'label': '', 'selected': ''}) continue;
+                input_elem.attr(key, options[idx][key]);
             }
         }
-        return this.element;
     }
 
     update_input(spec: any): any {
@@ -69,11 +77,21 @@ export class CheckboxRadio extends InputItem {
             });
         }
 
+        if ('options' in attributes) {
+            this.spec.options = attributes.options;
+            let spec = this.setup_spec();
+            const html = Mustache.render(options_tpl, spec);
+            this.element.find('.form-check').remove();
+            this.element.find('.invalid-feedback').before(html);
+            this.setup_input_options(this.element, spec.options);
+            delete attributes['options'];
+        }
+
         if ('valid_status' in attributes) {
             this.element.find('.invalid-feedback,.valid-feedback').hide();
-            if(attributes.valid_status===true)
+            if (attributes.valid_status === true)
                 this.element.find('.valid-feedback').show();
-            else if (attributes.valid_status===false)
+            else if (attributes.valid_status === false)
                 this.element.find('.invalid-feedback').show();
         }
         this.update_input_helper(idx, attributes);

+ 24 - 14
webiojs/src/models/input/select.ts

@@ -2,14 +2,16 @@ import {InputItem} from "./base";
 import {Session} from "../../session";
 import {deep_copy} from "../../utils"
 
-
+const options_tpl = `
+{{#options}}
+<option {{#selected}}selected{{/selected}} {{#disabled}}disabled{{/disabled}}>{{label}}</option>
+{{/options}}
+`;
 const select_input_tpl = `
 <div class="form-group">
     {{#label}}<label for="{{id_name}}">{{label}}</label>{{/label}}
     <select id="{{id_name}}" aria-describedby="{{id_name}}_help" class="form-control" {{#multiple}}multiple{{/multiple}}>
-        {{#options}}
-        <option {{#selected}}selected{{/selected}} {{#disabled}}disabled{{/disabled}}>{{label}}</option>
-        {{/options}}
+        ${options_tpl}
     </select>
     <div class="invalid-feedback">{{invalid_feedback}}</div>
     <div class="valid-feedback">{{valid_feedback}}</div>
@@ -29,18 +31,21 @@ export class Select extends InputItem {
         spec['id_name'] = id_name;
 
         let html = Mustache.render(select_input_tpl, spec);
-
         this.element = $(html);
-        let input_elem = this.element.find('#' + id_name);
-
-        let opts = input_elem.find('option');
-        for (let idx = 0; idx < spec.options.length; idx++)
-            opts.eq(idx).val(JSON.stringify(spec.options[idx].value));
+        this.setup_select_options(this.element, spec.options);
 
         // blur事件时,发送当前值到服务器
-        input_elem.on("blur", (e) => {
-            this.send_value_listener(this, e)
+        this.element.find('select').on("blur", (e) => {
+            this.send_value_listener(this, e);
         });
+        return this.element;
+    }
+
+    setup_select_options(elem: JQuery, options: any) {
+        let input_elem = elem.find('select');
+        let opts = input_elem.find('option');
+        for (let idx = 0; idx < options.length; idx++)
+            opts.eq(idx).val(JSON.stringify(options[idx].value));
 
         // 将额外的html参数加到input标签上
         const ignore_keys = {
@@ -57,13 +62,18 @@ export class Select extends InputItem {
             if (key in ignore_keys) continue;
             input_elem.attr(key, this.spec[key]);
         }
-
-        return this.element;
     }
 
     update_input(spec: any): any {
         let attributes = spec.attributes;
 
+        if ('options' in attributes) {
+            const opts_html = Mustache.render(options_tpl, {options: attributes.options});
+            this.element.find('select').empty().append(opts_html);
+            this.setup_select_options(this.element, attributes.options);
+            delete attributes['options'];
+        }
+
         this.update_input_helper(-1, attributes);
     }