【问题标题】:How can i dynamically add an Input select element on click of a button in ember如何在单击 ember 中的按钮时动态添加输入选择元素
【发布时间】:2022-10-05 16:51:24
【问题描述】:

我正在创建一个 ember 应用程序,其中需要动态添加一个选择元素,该元素将具有从服务器获取的选项。所以选择元素看起来像这样。 而不是预定义所有下拉框,我需要动态添加它们,就像点击按钮一样(+添加更多)。喜欢

每个下拉框都应该包含从服务器获取的数据。另外,我需要一种从那些动态创建的选择字段中获取数据的方法。

我当前下拉页面的 .hbs 是..

地图.hbs

<center><h4>Map</h4></center>
<container class = \"cond\">
{{#each this.model.sf as |row|}}
    <select class = \"sel\">
        {{#each this.model.sf as |sf|}}
        <option value = {{sf.attrname}}>{{sf.attrname}}</option>
        {{/each}}
        
    </select><br>
{{/each}}

我尝试了 ember-dynamic-fields 但它已被弃用,我无法使用它.. 以及网络上的所有其他解决方案或旧版本的 ember 方式.. 在 ember 4.6 上没有任何作用,所以有人可以帮忙吗?

    标签: dom ember.js handlebars.js


    【解决方案1】:

    使用该平台的原生 FormData 功能,demo'd here

    我认为我们可以通过以下方式根据输入数据生成任意数量的输入:

    • 将表单的状态存储在某个变量中
    • 根据该表单状态下的属性有条件地显示进一步的选择/输入。

    代码方面,看起来像这样:

    {{#if (dataHasValueFor "fieldName")}}
      Show previously hidden field
    {{/if}}
    

    当然,魔鬼在实现细节中,所以,一个完整的工作示例(使用我制作的示例数据——如果您想要针对您的特定数据集,我们可以对此进行迭代,只需在此帖子/答案上发表评论) .

    import Component from '@glimmer/component';
    import { tracked } from '@glimmer/tracking';
    import { on } from '@ember/modifier';
    import { get } from '@ember/helper';
    
    // This could be your model data from your route
    const DATA = {
      fruits: [ 
        'apple', 'banana', 'orange', 'mango', 
        'watermellon', 'avacado', 'tomato?'
      ],
      veggies: ['cocumber', 'tomato?', 'green bean', 'kale', 'spinach'], 
      peppers: ['carolina reaper', 'habanero', 'jalapeño']
    }
    
    export default class Demo extends Component {
      @tracked formData;
    
      get categories() {
        return Object.keys(DATA);
      }
    
      handleInput = (event) => {
        let formData = new FormData(event.currentTarget);
        let data = Object.fromEntries(formData.entries());    
    
        this.formData = data;
      }
    
      handleSubmit = (event) => {
        event.preventDefault();
        handleInput(event);
      }
    
      isSelected = (name, value) => this.formData?.[name] === value;
      
      <template>
        <form
          {{on 'input' this.handleInput}}
          {{on 'submit' this.handleSubmit}}
        >
          <label>
            Food Category<br>
            <select name="category" placeholder="Select...">
              <option selected disabled>Select a food group</option>
              {{#each this.categories as |name|}}
                <option 
                  value={{name}} 
                  selected={{this.isSelected "category" name}}
                 >
                  {{name}}
                </option>
              {{/each}}
            </select>
          </label>
    
          <hr>
          {{#let (get this.formData "category") as |selectedCategory|}}
            {{#if selectedCategory}}
              <label>
                {{selectedCategory}}<br>
                <select name={{selectedCategory}}>
                  <option selected disabled>
                    Select {{selectedCategory}}
                  </option>
                  {{#each (get DATA selectedCategory) as |food|}}
                    <option 
                      value={{food}} 
                      selected={{this.isSelected selectedCategory food}}
                    >
                     {{food}}
                    </option>
                  {{/each}}
                </select>
              </label>
            {{/if}}
          {{/let}}
    
      
        </form>
        <hr>
        FormData:
        <pre>{{toJson this.formData}}</pre>
      </template>
    }
    
    
    const toJson = (input) => JSON.stringify(input, null, 4);          
    

    这个演示是交互式的here, on limber.glimdown.com

    请注意,此处使用的语法是即将到来的默认语法PolarisEmber 版本,可通过ember-template-imports 获取


    更新(在 cmets 之后)

    Demo here

    我对如何字段是动态的,因为我认为这更容易显示问题中提出的概念:在表单中动态显示字段。

    import Component from '@glimmer/component';
    import { tracked } from '@glimmer/tracking';
    import { on } from '@ember/modifier';
    import { get } from '@ember/helper';
    
    export default class Demo extends Component {
      @tracked formData;
    
      handleInput = (event) => {
        let formData = new FormData(event.currentTarget);
        let data = Object.fromEntries(formData.entries());    
    
        this.formData = data;
      }
    
      handleSubmit = (event) => {
        event.preventDefault();
        handleInput(event);
      }
    
      <template>
        <form
          {{on 'input' this.handleInput}}
          {{on 'submit' this.handleSubmit}}
        > 
          <div class="grid">
            <label>
              Name <input type="checkbox" name='hasName'>
            </label>
            <label>
              Email <input type="checkbox" name='hasEmail'>
            </label>
            <label>
              Alias <input type="checkbox" name='hasAlias'>
            </label>
    
            <hr>
          
            {{#if (get this.formData 'hasName')}}
               <label>
                 Name
                 <input type="text" name="name" class="border" />
               </label>
            {{/if}}
            {{#if (get this.formData 'hasEmail')}}
               <label>
                 Email
                 <input type="email" name="email" class="border" />
               </label>
            {{/if}}
            {{#if (get this.formData 'hasAlias')}}
               <label>
                 Alias
                 <input type="text" name="alias" class="border" />
               </label>
            {{/if}}
    
          </div>
        
        </form>
        <hr>
        FormData:
        <pre>{{toJson this.formData}}</pre>
      </template>
    }
    
    
    const toJson = (input) => JSON.stringify(input, null, 4);          
    

    而且......因为您似乎有很多领域,您可能希望尽可能动态:

    demo here

    这是以下代码:

      <form
          {{on 'input' this.handleInput}}
          {{on 'submit' this.handleSubmit}}
        > 
          <div class="grid">
            {{#each FIELDS as |field|}}
              <label>
                {{field}} <input type="checkbox" name='has-{{field}}'>
              </label>
            {{/each}}
            <hr>
    
            {{#each FIELDS as |field|}}
              {{#if (get this.formData (concat 'has-' field))}}
                 <label>
                   {{field}}
                   <input type="text" name={{field}} class="border" />
                 </label>
              {{/if}}
            {{/each}}
           
          </div>
        </form>
    

    【讨论】:

    • hi.. thank you.. but what i needed was.. instead of those multiple select columns i need one as default and if user wants another there should be a button like add more and when selected a new select field should appear
    • 抱歉,如果我无法正确传达它..现在我已经更新了问题
    • 不用担心,所以澄清一下:您希望在用户单击按钮时显示选择输入吗?你想让这无限发生吗?所有选择都放在一个数组中吗?
    • 对于选项框中列出的所有选项.. 例如,如果选择具有 [email,name,alias] 之类的选项,则用户首先选择电子邮件,然后单击添加更多现在该选项应包含 [name,alias] 用户可以停在他愿意的地方,也可以继续,直到选项中的所有内容都被填写为止。
    • 更新了——概念基本相同——我使用了输入,因为它们比选择简单得多
    【解决方案2】:

    我猜简单的 js 代码确实具有添加和检索数据的魔力。发现后我很遗憾。对于一些动态的 ember formdata,nullvox 的先前答案有所帮助。所以这里是代码

    .hbs

    <table class="table">
        <th>
        <td>Sf</td>
        </th>
        <th>
        <td>Db</td>
        </th>
    
        <tbody id = "map">
    
       </tbody>
    
    
       </table>
       <button class = "btn btn-sm btn-primary" type="button" {{action "submit"}}>Submit</button>
       <button class = "btn btn-success btn-sm" onclick = {{action "get"}} type="button">Add another</button>
    

    用于创建元素的控制器代码

     @action
      get() {
        let div = document.getElementById('map');
        let tr = document.createElement('tr');
        let td = document.createElement('td');
        let td2 = document.createElement('td');
        var select = document.createElement('select');
        select.setAttribute('class', 'sfselect');
        div.appendChild(tr);
        tr.appendChild(td);
        td.appendChild(select);
    
        for (var i = 0; i < sf.length; i++) {
          var option = document.createElement('option');
          option.value = sf[i];
          option.text = sf[i];
          select.appendChild(option);
        }
        var select2 = document.createElement('select');
        select2.setAttribute('class', 'dbselect');
        tr.appendChild(td2);
        td2.appendChild(select2);
    
        for (var i = 0; i < db.length; i++) {
          var option = document.createElement('option');
          option.value = db[i];
          option.text = db[i];
          select2.appendChild(option);
        }
      }
    
    

    获取数据的控制器代码

      @action submit() {
        var sfattr = document.querySelectorAll('.sfselect');
        var dbattr = document.querySelectorAll('.dbselect');
        var sf = [];
        var db = [];
        console.log(sfattr.length);
        let datas;
        for (var i = 0; i < sfattr.length; i++) {
          sf[i] = sfattr[i].value;
          db[i] = dbattr[i].value;
        }
        let m1 = sf.toString();
        let m2 = db.toString();
        $.ajax({
          url: 'http://localhost:8080/lorduoauth/Map',
          method: 'POST',
          contentType: 'application/x-www-form-urlencoded',
          data: {
            m1: m1,
            m2: m2,
          },
    
          success: function (response) {
            console.log(datas);
            alert(response);
          },
          error: function (xhr, status, error) {
            var errorMessage = xhr.status + ': ' + xhr.statusText;
            alert('error' + errorMessage);
          },
        });
      }
    

    因此输出看起来像这样

    【讨论】:

      猜你喜欢
      • 2018-05-21
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多