深度思维者

永远年轻,永远热泪盈眶

Bootstrap, 模态框实现值传递,自动勾选

Bootstrap,模态框自动勾选,值传递

场景:

​ 有一个这样的需求, 在父页面有一个table, 在table中有每一行都有一个更新按钮, 用来更新此行数据关联的另一组完整数据, 在点击按钮时, 直接弹出新的table, 并且需要将默认已经关联的数据进行勾选处理. 如下所示.

过程.gif

1.父页面

效果

  1. 图一为父页面 domain_list : 展示某列表信息,其中绑定主机 是涉及调用 子页面的 btn

父页面.png

  1. 此页面代码如下, (后端主要使用了python, Django, 使用了模板语言. 这里不是重点)

    {% extends '_base_list.html' %}
    {% load i18n static %}
    {% block custom_head_css_js %}
    <style>
      #domainSteps {
        padding-left: 7%;
        width: 35%;
        margin:10px auto;
      }
    
      .step-item {
        display: inline-block;
        line-height: 32px;
        position: relative;
      }
    
      .step-item-tail {
        width: 100%;
        padding: 0 10px;
        position: absolute;
        left: 15px;
        top: 15px;
      }
    
      .step-item-tail i {
        display: inline-block;
        width: 100%;
        height: 3px;
        vertical-align: top;
        background: #2061FF;
        position: relative;
      }
    
      .step-item-tail-done {
        background: #2061FF !important;
      }
    
      .step-item-head {
        position: relative;
        display: inline-block;
        height: 32px;
        width: 32px;
        text-align: center;
        vertical-align: top;
        color: #2061FF;
        border: 1px solid #2061FF;
        border-radius: 50%;
      }
    
      .step-item-head.step-item-head-active {
        background: #2061FF;
        color: #ffffff;
      }
    
      .step-item-main {
        display: block;
        position: relative;
        left: -9px;
      }
    
      .step-item-main-title {
        font-weight: 500;
        color: #4B556A;
      }
    
      .step-item-main-desc {
        color: #aaaaaa;
      }
      /*搜索框样式*/
      #domain_list_table_filter input {
        border: 1px solid #D0D2D7;
      }
    
      #domain_list_table_filter input:focus {
        border: 1px solid rgb(32, 97, 255) !important;
      }
    </style>
    {% endblock %}
    {% block table_search %}{% endblock %}
    {% block help_message %}
    <div id="domainSteps"></div>
    
    {% endblock %}
    
    {% block table_container %}
    <div class="uc pull-left  m-r-5">
      <a href="/ops-audit{% url 'assets:domain-create' %}" class="btn btn-sm btn-primary">
        <i class="layui-icon" style="font-size: 12px;">&#xe654;</i>
        {% trans "Create domain" %}
      </a>
    </div>
    <table class="table table-hover" id="domain_list_table">
      <thead>
        <tr>
          <th class="text-center">
            <input type="checkbox" id="check_all" class="ipt_check_all">
          </th>
          <th class="text-center">{% trans 'Name' %}</th>
          <th class="text-center">{% trans 'Asset' %}</th>
          <th class="text-center">{% trans 'Gateway' %}</th>
          <th class="text-center">{% trans 'Comment' %}</th>
          <th class="text-center">{% trans 'Action' %}</th>
        </tr>
      </thead>
      <tbody>
      </tbody>
    </table>
    {% include 'assets/_asset_list_modal.html' %}
    {% endblock %}
    
    {% block content_bottom_left %}{% endblock %}
    {% block custom_foot_js %}
    <script>
    
    function initTable() {
        var options = {
            ele: $('#domain_list_table'),
            columnDefs: [
            {
              targets: 1, createdCell: function (td, cellData, rowData) {
                var detail_btn = '<a href="/ops-audit{% url "assets:domain-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
                $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
              }
            },
            {
              targets: 3, createdCell: function (td, cellData, rowData) {
                var gateway_list_btn = '<a href="/ops-audit{% url "assets:domain-gateway-list" pk=DEFAULT_PK %}">' + cellData + '</a>';
                gateway_list_btn = gateway_list_btn.replace("{{ DEFAULT_PK }}", rowData.id);
                $(td).html(gateway_list_btn);
              }
            },
            {
              targets: 5, createdCell: function (td, cellData, rowData) {
                var bindHost = '<a  class="m-l-xs btn-bind"  data-aid="{{ DEFAULT_PK }}"  >{% trans "Bind assets" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
                var update_btn = '<a href="/ops-audit{% url "assets:domain-update" pk=DEFAULT_PK %}" class="">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
                var del_btn = '<a class="m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
                $(td).html(bindHost+"<span style='color:#D9D9D9'> | </span>"+update_btn+"<span style='color:#D9D9D9'> | </span>"+del_btn)
              }
            }
            ],
            ajax_url: '/ops-audit{% url "api-assets:domain-list" %}',
            columns: [
                { data: "id" }, { data: "name",orderable: false }, { data: "asset_count",orderable: false },
                { data: "gateway_count",orderable: false }, { data: "comment",orderable: false }, { data: "id",orderable: false }
            ],
            op_html: $('#actions').html()
            };
        jumpserver.initServerSideDataTable(options);
    }
    $(document).ready(function () {
        initTable();
        layui.use('steps', function () {
            var steps = layui.steps;
    
            var dataDomain = [
                { 'title': "创建网域"},
                { 'title': "创建网关"},
                { 'title': "绑定主机"}
    
            // { 'title': "第三步", "desc": "2018-07-01 10:44:42" }
            ];
    
            steps.make(dataDomain, '#domainSteps', 0);
            });
            //搜索框icon
            var html = '<span class="searchTubiao fa fa-search" id="searchTubiao"></span>';
            $("#domain_list_table_filter").append(html);
    })
    
    .on('click', '.btn-delete', function () {
        var $this = $(this);
        var $data_table = $('#domain_list_table').DataTable();
        var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
        var uid = $this.data('uid');
        var the_url = '/ops-audit{% url "api-assets:domain-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
        objectDelete($this, name, the_url);
        setTimeout(function () {
        $data_table.ajax.reload();
        }, 1500);
    })
    .on('click', '.btn-bind', function () {
        var $this = $(this);
        var aid = $this.data('aid');
        var $id_assets = $('#id_assets');
        $id_assets.attr("aid",aid);
        $('#asset_list_modal').modal('show');
    });
    </script>
    
    <script>
        // after bound assets,updated domain table.
        $(function() {
            var $data_table = $('#domain_list_table').DataTable();
            $('#asset_list_modal').on('hide.bs.modal',
                                      function() {
                setTimeout(function () {
                    $data_table.ajax.reload();
                }, 1000);
            })
        });
    </script>
    {% endblock %}
    

代码分析

  1. body代码块中, {% include 'assets/_asset_list_modal.html' %} 是用来加载bootstrap的模态框,即子页面

  2. initTable() 用来初始化父页面的table. 重点在 targets: 5, createdCell: function (td, cellData, rowData) 第六列展示了三个button样式. 分别是 bindHost(绑定主机), update_btn(更新), del_btn(删除), 每一个button上面绑定一个``click 事件, 事件再绑定api`接口

  3. 删除btn事件如下,不多赘述

    <script>
       ...
    .on('click', '.btn-delete', function () {
        var $this = $(this);
        var $data_table = $('#domain_list_table').DataTable();
        var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
        var uid = $this.data('uid');
        var the_url = '/ops-audit{% url "api-assets:domain-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
        objectDelete($this, name, the_url);
        setTimeout(function () {
        $data_table.ajax.reload();
        }, 1500);
    })
    <script>
    
  4. 绑定主机btn click事件如下

    <script>
    .on('click', '.btn-bind', function () {
        var $this = $(this);
        var aid = $this.data('aid');
        var $id_assets = $('#id_assets');
        $id_assets.attr("aid",aid);
        $('#asset_list_modal').modal('show');
    });
    </script>
    

    说明

    • 此点击事件其实实现了两个api的调用①获取当前绑定资产的原有列表;②更新domain资产
    • aid为当前domain的pk值,用来传递给子页面, 然后调用相应的api
    • #id_assets为子页面中 <input>标签 id值, 用来接收父页面传递子页面的值
    • #asset_list_modal 为子页面 modal(模态框) id值

2. 子页面(modal) 模态框

效果

  1. 子页面assets_list用来展示所有的资产; 初始化时, 必须勾选已经绑定的资产; 提交按钮时用来 更新domain的assets.

子页面.png

  1. 代码如下
{% extends '_modal.html' %}
{% load i18n %}
{% load static %}

{% block modal_class %}modal-lg{% endblock %}
{% block modal_id %}asset_list_modal{% endblock %}
{% block modal_title%}{% trans "Asset list" %}{% endblock %}


{% block modal_body %}
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<style>
.inmodal .modal-header {
    padding: 10px 10px;
    text-align: center;
}

#assetTree2.ztree * {
    background-color: #f8fafb;
}
#assetTree2.ztree {
    background-color: #f8fafb;
}
</style>

<input type="text"  name="id_assets" style="visibility: hidden" id="id_assets"  value="">

<div class="wrapper wrapper-content">
   <div class="row">
       <div class="col-lg-3" id="split-left" style="padding-left: 3px">
           <div class="ibox float-e-margins">
               <div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
                   <div class="file-manager ">
                       <div id="assetTree2" class="ztree">
                       </div>
                       <div class="clearfix"></div>
                   </div>
               </div>
           </div>
       </div>

       <div class="col-lg-9 animated fadeInRight" id="split-right">
           <div class="mail-box-header">
               <table class="table table-striped table-bordered table-hover " id="asset_list_modal_table" style="width: 100%">
                   <thead>
                       <tr>
                           <th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
                           <th class="text-center">{% trans 'Hostname' %}</th>
                           <th class="text-center">{% trans 'IP' %}</th>
                       </tr>
                   </thead>
                   <tbody>
                   </tbody>
               </table>
           </div>
       </div>
   </div>
</div>

<script>
var zTree2, asset_table2 = 0;
// 获取资产列表
function initTable2() {
    if(asset_table2){
        return
    }

    var options = {
        ele: $('#asset_list_modal_table'),
        ajax_url: '/ops-audit{% url "api-assets:asset-list" %}?show_current_asset=1',
        columns: [
            {data: "id"}, {data: "hostname" }, {data: "ip" }
        ],
        pageLength: 10
    };
    asset_table2 = jumpserver.initServerSideDataTable(options);
    console.log();
    return asset_table2
}

// 初始化时选中 已经绑定的资产
//function onNodeSelected2(event, treeNode) {
//    var url = asset_table2.ajax.url();
//    url = setUrlParam(url, "node_id", treeNode.meta.node.id);
//    asset_table2.ajax.url(url);
//    asset_table2.ajax.reload();
// }

// 获取节点
function initTree2() {
    var url = '/ops-audit{% url "api-assets:node-children-tree" %}?assets=0';
    var setting = {
        view: {
            dblClickExpand: false,
            showLine: true
        },
        data: {
            simpleData: {
                enable: true
            }
        },
        async: {
			enable: true,
			url: url,
			autoParam: ["id=key", "name=n", "level=lv"],
            type: 'get'
		},
        callback: {
            onSelected: onNodeSelected2
        }
    };
    zTree2 = $.fn.zTree.init($("#assetTree2"), setting);
}

function initSelectedAssets(){
        let init_bound_assets = [];
        let $id_assets = $('#id_assets');
        let aid = $id_assets.attr('aid');
        let api_url = '{% url "api-assets:domain-assets-update" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", aid);
        $.ajax({
            url: api_url,
            Type: 'GET',
            dataType: "json",
            sync: false,
            success :function (data) {
               let res_assets = data.result.assets;
               if  (res_assets.length !==0){
                    for (let i=0;i<res_assets.length;i++){
                        init_bound_assets.push(res_assets[i]);
                    }
               }else{
                    init_bound_assets = [];
               }
               $id_assets.attr("value",init_bound_assets);
               console.log("已绑定的资产:",init_bound_assets);
               correctSelectedCheckbox(init_bound_assets);
            },

            error: function(XMLResponse) {
               let error_msg = XMLResponse.responseText;
               let error_res =  JSON.parse(error_msg);
               console.error(error_res);
            }
        });
}

function correctSelectedCheckbox(init_bound_assets) {
    // var assets_table = document.getElementById('asset_list_modal_table');
    let selectedAssets = asset_table2.selected.concat();
    console.log("缓存资产1:",selectedAssets);
	
    // 防止上一次操作勾选后存在缓存
    if (selectedAssets.length !== 0 && init_bound_assets.length === 0) {
        $.each(selectedAssets, function(index, assetId) {
             $('#' + assetId).trigger('click'); // 取消勾选
        });
    }
    
    console.log("缓存资产2:",selectedAssets);
    if (selectedAssets.length !== 0 && init_bound_assets.length !== 0) {
        $.each(selectedAssets, function(index, AssetId) {
          if ($.inArray(AssetId, init_bound_assets) === -1) {
              $('#' + AssetId).trigger('click'); // 将错误勾选资产取消勾选
          }
        });

        $.each(init_bound_assets,function(index,AssetId) {
          if ($.inArray(AssetId, selectedAssets) === -1){
               $('#' + AssetId).trigger('click'); // 将未勾选的初始资产重新勾选
          }
        })
    }

    // 默认无勾选时,将已绑定的资产勾选上
    if (selectedAssets.length === 0 && init_bound_assets.length !== 0) {
        $.each(init_bound_assets,function(index,AssetId) {
            $('#' +  AssetId).trigger('click');
        });
    }
}

$(document).ready(function(){

})

.on('show.bs.modal', function () {
    initTable2();
    initTree2();
    initSelectedAssets();
})

// 提交按钮操作
.on('click','#btn_asset_modal_confirm', function (){
    let $id_assets = $('#id_assets');
    let aid = $id_assets.attr("aid");
    let update_assets = asset_table2.selected;
    console.log(update_assets);

    let api_url = '{% url "api-assets:domain-assets-update" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", aid);

    $.ajax({
        url: api_url,
        type: 'PUT',
        dataType: "json",
        data: JSON.stringify({
            assets: update_assets
        }),
        contentType:'application/json',
        sync: false,
        success :function (data) {
            let assets = data.result.assets;
            console.log(111,assets);

            $id_assets.attr("value",assets);
            console.log("更新后绑定的资产id:",$id_assets.val());
        },

        error: function(XMLResponse) {
            let error_msg = XMLResponse.responseText;
            let error_res =  JSON.parse(error_msg);
            console.error("request error:"+error_res);
        }
    });
    $("#asset_list_modal").modal('hide');
});

</script>
{% endblock %}

{% block modal_button %}
    {{ block.super }}
{% endblock %}

{% block modal_confirm_id %}btn_asset_modal_confirm{% endblock %}

代码分析

  1. {% extends '_modal.html' %} 说明此页面继承了_modal.html的父页面, 而父页面就是 模态框的一个模板

  2. 使用模块框继承时, 写法

    {% block modal_class %}modal-lg{% endblock %}   /
    {% block modal_id %}asset_list_modal{% endblock %} // 定义模板id,用于发页面的引用, 渲染页面时会自动将父页面中添加一个 <div>的标签,并将`asset_list_modal`做为id
    
  3. initTable2()用来初始化子页面 table

  4. initTree2() 用来获取节点

  5. correctSelectedCheckbox(init_bound_assets) , 将绑定的资产在table中进行勾选操作,

  6. initSelectedAssets() 获取已经绑定过的资产.

  7. 模态框显示时 event

    <script>
       ...
    .on('show.bs.modal', function () {
       initTable2();
       initTree2();
       initSelectedAssets();
    })
    </script>
    
  8. 提交btn事件如下

    <script>
    // 提交按钮操作
    .on('click','#btn_asset_modal_confirm', function (){
        let $id_assets = $('#id_assets');
        let aid = $id_assets.attr("aid");
        let update_assets = asset_table2.selected;
        let api_url = '{% url "api-assets:domain-assets-update" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", aid);
    
        $.ajax({
            url: api_url,
            type: 'PUT',
            dataType: "json",
            data: JSON.stringify({
                assets: update_assets
            }),
            contentType:'application/json',
            sync: false,
            success :function (data) {
                let assets = data.result.assets;
                console.log(111,assets);
    
                $id_assets.attr("value",assets);
                console.log("更新后绑定的资产id:",$id_assets.val());
            },
    
            error: function(XMLResponse) {
                let error_msg = XMLResponse.responseText;
                let error_res =  JSON.parse(error_msg);
                console.error("request error:"+error_res);
            }
        });
        $("#asset_list_modal").modal('hide');
    });
    </script>
    
  9. {% block modal_confirm_id %}btn_asset_modal_confirm{% endblock %} 定义提交按钮 id

posted @ 2019-12-06 15:25  failymao  阅读(935)  评论(0编辑  收藏  举报