javascript - How to traverse the functions and contents of dynamically added elements
代言
代言 2017-06-12 09:28:08
0
5
845

As shown in the figure: The function to be realized is to click the add button at the top and dynamically add table rows at the bottom, and then the content in each row is traversed from the object.
Then I only have the lines written in the first html that have content and functions.
The row that comes out after clicking the button has no content and no function. (Note: The function refers to my first column and second column, which are the secondary linkage effects)

The following is the code: (I am a novice, and I am not very familiar with jq, so the writing is very messy, and it is a mixture of js and jq =-=, please give me some advice and guidance!)

    <p class="clearfix" style="margin-left:200px;">
    <button class="button2" style="border:1px solid #000">添加</button>
    <form class="clearfix" style="float:left;margin-top:100px;">
        <table id="b" border="1px solid #000">
            <thead>
                <tr class="zzz">
                    <th style="width:141px;">计算期类型</th>
                    <th style="width:281px;">期间</th>
                    <th style="width:141px;">征收方式</th>
                </tr>
            </thead>
            <tbody id="zType_all">
                <tr>
                    <td>
                        <select id="zType_time"></select>
                    </td>
                    <td>
                        <select id="zType_years" style="float:left;"></select>
                        <select id="month_quarter"></select>
                    </td>
                    <td>
                        <select id="zCollection">
                            <option value="chazhang">查账征收</option>
                            <option value="heding">核定征收</option>
                        </select>
                    </td>
                </tr>
            </tbody>
        </table>
    </form>
    </p>
//点击按钮添加

    $('.button2').on('click',function(){
    var ccc = $('<tr><td><select id="zType_time"></select></td><td><select id="zType_years"></select><select id="month_quarter"></select></td><td><select id="zCollection"><option value="chazhang">查账征收</option><option value="heding">核定征收</option></select></td></tr>');
    var ddd = $('#zType_all');
    ddd.append(ccc);
    $('#a').css({"background":"white","color":"#000"});
    });



//下面是关于二级和三级联动的遍历
//这个是存储着option里信息的对象

    var zType_chose = [
    {
    "name":"年终汇算","types":[
        {"years":"2015年"},
        {"years":"2016年"}
        ]
     },
     {
        "name":"预缴-月度","types":[
        {"years":"2015年","zType_time1":["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"]},
        {"years":"2016年","zType_time1":["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"]}
        ]
     },
     {
        "name":"预缴-季度","types":[
        {"years":"2015年","zType_time1":["第一季度","第二季度","第三季度","第四季度"]},
        {"years":"2016年","zType_time1":["第一季度","第二季度","第三季度","第四季度"]}
        ]
     }
     ];

    //下面是我实现联动的js代码
    var zType_time = document.getElementById("zType_time");
    var zType_years = document.getElementById("zType_years");
    var month_quarter = document.getElementById("month_quarter");
    var zType_all = document.getElementById("zType_all");
    zType_time.options[0] = new Option("计算期类型");
    zType_years.options[0] = new Option("请选择年");
    month_quarter.options[0] = new Option("请选择月/季度");
    // 循环第一步把计算期类型循环进select
    for (var i = 0; i < zType_chose.length; i++) {
    zType_time.options[zType_time.length] = new Option(zType_chose[i].name);
    // 循环第二步,把第二列都循环进select
    zType_time.onchange = function(){
    zType_years.options.length = 0;
    month_quarter.options.length = 0;
    zType_years.options[zType_years.length] = new Option("请选择年");
    month_quarter.options[month_quarter.length] = new Option("请选择月/季度");
    for (var j = 0; j < zType_chose[zType_time.selectedIndex-1].types.length; j++) {
        zType_years.options[zType_years.length] = new Option(zType_chose[zType_time.selectedIndex-1].types[j].years)
    }
    if(zType_time.options[zType_time.selectedIndex].text == "年终汇算"){
        month_quarter.style.display = "none";
    }else{
        month_quarter.style.display = "inline-block";
    }
    }
    zType_years.onchange = function(){
        month_quarter.options.length = 0;
        month_quarter.options[month_quarter.length] = new Option("请选择月/季度");
        //循环另一个
        for (var k = 0; k < zType_chose[zType_time.selectedIndex-1].types[zType_years.selectedIndex-1].zType_time1.length; k++) {
            month_quarter.options[month_quarter.length] = new Option(zType_chose[zType_time.selectedIndex-1].types[zType_years.selectedIndex-1].zType_time1[k]);  
        };
    }
    };

I think maybe the content should be traversed when creating the rows of the table? But I don’t know how to do it, and what should I do with my function?
Waiting for a big guy online

tell me! Many thanks! urgent!

代言
代言

reply all(5)
typecho

First of all, id can only appear once in a page and is unique. Only class can appear multiple times!

Statement

id is the only attribute, that is, only one corresponding id can appear in a html file, and multiple class can be used;

Requirement realization

The front-end part, from the framework to the functions, can all be solved using design patterns. To put it bluntly, they can all be solved using MVC, as in your example:

  • C -> Entire JS logic;

  • V -> Single line entry;

  • M -> filled data;

You can actually encapsulate this kind of thing with a closure, or make it into a processing class. Such as:

<p class="clearfix" style="margin-left:200px;">
    <button class="button2" style="border:1px solid #000">添加</button>
    <form class="clearfix" style="float:left;margin-top:100px;">
        <table border="1">
            <thead>
                <tr class="zzz">
                    <th width="240">计算期类型</th>
                    <th width="240">期间</th>
                    <th width="128">征收方式</th>
                </tr>
            </thead>
            <tbody id="zType_all">
            </tbody>
        </table>
    </form>
</p>

Continue to improve the script:

(function($) {
    'use strict';

    /**
     * 组件条目解析
     * 一行即一个组件条目,该构造方法
     * 例:var thisRow = new AppRow();
     * @return {object} 一个 jQuery 对象
     */
    var AppRow = function() {
        return this.rowParse(this.rowDom());
    };

    // HTML 结构
    AppRow.prototype.rowDom = function() {
        var row = '',
            options = AppRow.typeChose,
            optionYears = options[0].types;

        // 计算期类型
        row += '<td><select class="type">';
        row += '<option value="-1">请选择</option>';
        for (var i in options) {
            row += '<option value="' + i + '">' + options[i].name + '</option>';
        }
        row += '</select></td>';

        // 期间
        row += '<td class="types"></td>';

        // 征收方式
        row += '<td><select class="collection">';
        row += '<option value="0">请选择</option>';
        row += '<option value="1">查账征收</option>';
        row += '<option value="2">核定征收</option>';
        row += '</select></td>';

        return '<tr>' + row + '</tr>';
    };

    // 解析行结构,添加事件
    AppRow.prototype.rowParse = function(row) {
        var $row = $(row),
            $typeTime = $row.find('select.type'),
            $typeTypes = $row.find('.types'),
            optionsData = AppRow.typeChose;

        // 计算期类型
        $typeTime.on('change.app', $.proxy(function(e) {
            var val = $typeTime[0].value;
            $typeTypes.children().remove();
            $typeTypes.append(this.selectYears(val));
        }, this));

        return $row;
    };

    // 返回年度表单
    AppRow.prototype.selectYears = function(type) {
        var optionYears = AppRow.typeChose[0].types,
            select = '',
            $select = null;

        // 构建表单
        select += '<select class="year">';
        select += '<option value="-1">请选择</option>';
        for (var i in optionYears) {
            select += '<option value="' + i + '">' + optionYears[i].years + '</option>';
        }
        select += '</select>';

        // 构建成 jQuery 对象
        $select = $(select);

        // 事件绑定
        $select.on({
            // 选择事件
            'change.app': $.proxy(function(e) {
                var val = $select[0].value,
                    $sub = $select.next('.sub');

                if (type <= 0) {
                    // 年终汇算无后续表单
                    return;
                }

                if (val === -1) {
                    // 未选择,则移除后续表单
                    $select.nextAll().remove();
                    return;
                }

                // 创建或或初始化后续表单
                if (!$sub.get(0)) {
                    // 表单不存在则创建
                    $select.after(this.selectSub(type, val));
                }
                $sub.trigger('reset.app');
            }, this),

            // 重置表单
            'reset.app': $.proxy(function(e) {
                $select.find('option').prop('selected', false)
                    .eq(0)
                    .prop('selected', true);
            })
        });

        return $select;
    };

    // 返回季度或月份表单
    AppRow.prototype.selectSub = function(type, year) {
        var optionData = AppRow.typeChose[type].types[year].zType_time1,
            select = '',
            $select = null;

        if (!optionData) {
            // 无数据
            return;
        }

        // 构建表单
        select += '<select class="sub">';
        select += '<option value="-1">请选择</option>';
        for (var i in optionData) {
            select += '<option value="' + i + '">' + optionData[i] + '</option>';
        }
        select += '</select>';
        $select = $(select);

        // 事件绑定
        $select.on({
            // 重置表单
            'reset.app': $.proxy(function(e) {
                $select.find('option').prop('selected', false)
                    .eq(0)
                    .prop('selected', true);
            })
        });

        return $select;
    };

    // 联动数据 - zType_chose
    AppRow.typeChose = [{
        "name": "年终汇算",
        "types": [{
            "years": "2015年"
        }, {
            "years": "2016年"
        }]
    }, {
        "name": "预缴-月度",
        "types": [{
            "years": "2015年",
            "zType_time1": ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]
        }, {
            "years": "2016年",
            "zType_time1": ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]
        }]
    }, {
        "name": "预缴-季度",
        "types": [{
            "years": "2015年",
            "zType_time1": ["第一季度", "第二季度", "第三季度", "第四季度"]
        }, {
            "years": "2016年",
            "zType_time1": ["第一季度", "第二季度", "第三季度", "第四季度"]
        }]
    }];

    AppRow.VERSION = '1.0.0';

    // ===========================================

    // 添加按钮事件绑定
    var $addBtn = $('.button2'),
        $rowList = $('#zType_all');

    // 点击添加
    $addBtn.on('click.app', function(e) {
        // 或直接添加实例
        $rowList.append(new AppRow());
    });

})(jQuery);

Explanation

  • Create a constructor to generate a structure with interactive encapsulation effect - component;

  • Add a series of methods to the component and create logic inside;

  • Closure encapsulation refers to only taking effect in (function($){ /*code*/ })(jQuery);;

  • $.fn.remove can ensure the security of the data on the page. Do not use $.fn.hide

  • You can also use AppRow.prototype.delete() to extend delete operations, etc.;

  • If you need to use name for data submission, you need to use the format of name="row[index][name]", such as: name="row[1]['type']", name="row[1]['year']"name="row[1]['sub']";

Final effect:

Online effect

https://jsfiddle.net/kxjyo7fp...

某草草

Put the code for traversing the data in the method where you click to add a row. The specific coordination is how to add a row and traverse one. You have to implement this yourself. I didn't look into it carefully. You are now a bit like a dynamically added element. You bind the event, and the result is bound in the HTML written, but the added element is not bound to the event

学霸

It is recommended to use the ui library directly. For jquery, you can choose easyui / bootstrap table

学习ing

Event binding will be successfully bound after the page rendering is completed, and will not be automatically bound afterwards. That is, nodes added after the page is rendered cannot be bound. What we are talking about here is $('.a').click (...) This is a similar method because when it is compiled for the first time, an event will be bound to the class A on the page. If you dynamically condition several nodes with class a in JS, then adding them later will have no effect. , because the node added later does not exist when binding for the first time.
The solution is to use the on() method. For example, $('body').on('click','.a',fun(){}) This method is fine, because the body tag will exist no matter when. Therefore, there will be no situation where the node cannot be found and cannot be bound.
Of course, you can also write the function on the node yourself, but this is not recommended.

小葫芦

I rewrote part of the script to generate DOM using jQuery. For speed, I used some ES6 syntax. But the function is not completed yet

https://jsfiddle.net/jrhju549/1/

Then when I was thinking about cascading this part of things, I found a problem (about data):

From the data point of view, the optional data for monthly payment and quarter are the same no matter what year it is. Month is 12 months and quarter is 4 quarters. Then these data are actually fixed and can be written directly in HTML. In this way, when generating new rows, you only need to clone them first and then handle the details, which is much simpler.

However, another possibility cannot be ruled out, that is, your options are different every year. For example, 2015 is 12 months, 2016 is 8 months... (Of course, the possibility of this situation is very low), in this case, the select can be dynamically generated based on this data. Then before dynamically generating select, you need to use a findXxxx function to find the data that the corresponding option list needs to use - this process will of course be much more complicated.

Looking at the current progress, here are a few main points

Modular processing

Don’t think of doing everything in one function, split it up. For example, I initially split createRow and createSelect in the code. Among them, createSelect is highly reusable

// 创建 select,items 是数据 map 是名称映射表
// 如果名称本来就是按 value 和 text 来命名,就不需要映射表
function createSelect(items, map = {}) {
    const value = map.value || "name";
    const text = map.text || "text";
    const $options = items
        .map(t => $("<option>").prop({ value: t[value] }).text(t[text] || ""));
    return $("<select>").append(...$options);
}
// 创建一个 tr,含 td 和初始化的 select
function createRow() {
    var $tr = $("<tr>");
    var $tds = Array.from(Array(3))
        .map(() => $("<td>"));

    createSelect(types).appendTo($tds[0]);

    createSelect([
        { value: "chazhang", text: "查账征收" },
        { value: "heding", text: "核定征收" }
    ]).appendTo($tds[2]);

    return $tr.append(...$tds);
}

Organize the data first

Because the DOM structure is generated based on data, the data is very important. The intuitive way is to search for the data at the same time, but this way the code looks messy. Therefore, it is generally recommended to organize and prepare the corresponding data first, and then generate DOM based on the organized data

For example, types is extracted from zType_chose first

// 生成类型数据
var types = [{ text: "计算机期类型" }]
    .concat(zType_chose.map(t => ({
        value: t.name,
        text: t.name
    })));

When sorting list data, map, filter and reduce are basically standard (for more complex situations, you can consider RxJs)

You have changed id to class, which is good, clearing the way for later use $.fn.close(). Since I don't have much time to go further, I'll leave the question to you: consider defining select in HTML, and then handle the details (such as hiding) in code. If the select still needs to be defined based on data, you can fill in all the first select at the beginning to facilitate cloning later - of course in this case, the process of perfecting tr is encapsulated in a function, and you don't even need to clone. You can also create tr directly.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template