Bootstrap,模态框自动勾选,值传递
场景:
有一个这样的需求, 在父页面有一个table, 在table中有每一行都有一个更新按钮, 用来更新此行数据关联的另一组完整数据, 在点击按钮时, 直接弹出新的table, 并且需要将默认已经关联的数据进行勾选处理. 如下所示.
1.父页面
效果
- 图一为父页面 domain_list : 展示某列表信息,其中
绑定主机
是涉及调用 子页面的 btn
此页面代码如下, (后端主要使用了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;"></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 %}
代码分析
body代码块中,
{% include 'assets/_asset_list_modal.html' %}
是用来加载bootstrap的模态框,即子页面initTable()
用来初始化父页面的table. 重点在targets: 5, createdCell: function (td, cellData, rowData)
第六列展示了三个button样式. 分别是bindHost(绑定主机)
,update_btn(更新)
,del_btn(删除)
, 每一个button上面绑定一个`click
事件, 事件再绑定api
接口删除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>
绑定主机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) 模态框
效果
- 子页面assets_list用来展示所有的资产; 初始化时, 必须勾选已经绑定的资产; 提交按钮时用来 更新domain的assets.
- 代码如下
{% 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 %}
代码分析
{% extends '_modal.html' %}
说明此页面继承了_modal.html
的父页面, 而父页面就是 模态框的一个模板使用模块框继承时, 写法
{% block modal_class %}modal-lg{% endblock %} / {% block modal_id %}asset_list_modal{% endblock %} // 定义模板id,用于发页面的引用, 渲染页面时会自动将父页面中添加一个 <div>的标签,并将`asset_list_modal`做为id
initTable2()
用来初始化子页面 tableinitTree2()
用来获取节点correctSelectedCheckbox(init_bound_assets)
, 将绑定的资产在table中进行勾选操作,initSelectedAssets()
获取已经绑定过的资产.模态框显示时 event
<script> ... .on('show.bs.modal', function () { initTable2(); initTree2(); initSelectedAssets(); }) </script>
提交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>
{% block modal_confirm_id %}btn_asset_modal_confirm{% endblock %}
定义提交按钮 id