Bootstrap 5 模态和 jQuery 验证
Bootstrap 5 Modal and jQuery Validation
我正在尝试将项目添加到动态拖放列表(来自 here 的 Nestable 2,我已经很清楚了。
我正在使用 Bootstrap 5 模式来获取输入。也在工作。
现在我在表单输入中添加 jQuery validation。就验证而言,这也有效。
但是,当我添加第二个项目时,我添加了两个新项目。第三次尝试时,我添加了三个项目。
这是我的表单提交代码:
// Enable drag and drop nest structure
$('#navTree').nestable({maxDepth: 2}).on();
// Last ID of current nav tree - needed to add new nav items - passed from server side as hidden input value
var lastID = $('#lastID').val();
console.log('Start ID: ' + lastID);
// jQuery Validator - Validation Settings for AddNav form
var validatorAddNav = $("#frmAddNav").validate(
{
rules:
{
formPage:
{
required: true,
letterswithbasicpunc: true,
rangelength: [3, 20]
}
},
errorPlacement: function(error, element)
{
errorInsert = "#" + element.attr("name") + "Error";
error.appendTo(errorInsert);
},
highlight: function(element){$(element).addClass("is-invalid").removeClass("is-valid");},
unhighlight: function(element){$(element).addClass("is-valid").removeClass("is-invalid");}
});
// AddNav Modal Activated
$("#modalAddNav").on('shown.bs.modal',function()
{
console.log('AddNav Modal Shown');
// Set AddNav form focus
$(this).find('#formPage').focus();
$('#btnAddNav').click(function(e)
{
e.preventDefault(); // Prevent default POST submit
if ($("#frmAddNav").valid())
{
var newID = ++lastID;
var newPage = $('#formPage').val();
console.log('Add Button on ID: ' + newID);
var newLI =
'<li id="navItem' + newID + '" class="dd-item dd3-item" data-file="file' + newID + '.php" data-nav="Nav ' + newID + '" data-page="Page ' + newID + '" data-id="' + newID + '">' +
' <div class="dd-handle dd3-handle">Drag</div>' +
' <div class="dd3-content"><div id="entry1">' + newPage + ' ' + newID + '</div></div>' +
'</li>';
$('#modalAddNav').modal('hide'); // Close Modal
validatorAddNav.resetForm();
$('#navTree > .dd-list').append(newLI); // Add Nav Item to Tree
};
});
});
// Save Nav Tree - this is where form validation and AJAX will need to go
$('#ajaxSave').click(function(e)
{
var navTree = JSON.stringify($('#navTree').nestable('serialize'));
console.log('Nav Tree:\n' + navTree + '\n\n');
});
.dd
{
max-width: 700px;
}
/** Nestable Draggable Handles */
.dd3-content
{
display: block;
height: 30px;
margin: 5px 0;
padding: 5px 10px 5px 40px;
color: #333;
text-decoration: none;
font-weight: bold;
border: 1px solid #ccc;
background: #fafafa;
background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
background: linear-gradient(top, #fafafa 0%, #eee 100%);
-webkit-border-radius: 3px;
border-radius: 3px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
.dd3-content:hover
{
color: #2ea8e5;
background: #fff;
}
.dd-dragel > .dd3-item > .dd3-content
{
margin: 0;
}
.dd3-item > button
{
margin-left: 30px;
}
.dd3-handle
{
position: absolute;
margin: 0;
left: 0;
top: 0;
cursor: pointer;
width: 30px;
text-indent: 30px;
white-space: nowrap;
overflow: hidden;
border: 1px solid #aaa;
background: #ddd;
background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
background: linear-gradient(top, #ddd 0%, #bbb 100%);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.dd3-handle:before
{
content: '≡';
display: block;
position: absolute;
left: 0;
top: 3px;
width: 100%;
text-align: center;
text-indent: 0;
color: #fff;
font-size: 20px;
font-weight: normal;
}
.dd3-handle:hover
{
background: #ddd;
}
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha512-aOG0c6nPNzGk+5zjwyJaoRUgCdOrfSDhmMID2u4+OIslr0GjpLKo7Xm0Ao3xmpM4T8AmIouRkqwj1nrdVsLKEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.css" integrity="sha512-yOW3WV01iPnrQrlHYlpnfVooIAQl/hujmnCmiM3+u8F/6cCgA3BdFjqQfu8XaOtPilD/yYBJR3Io4PO8QUQKWA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Include JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.js" integrity="sha512-7bS2beHr26eBtIOb/82sgllyFc1qMsDcOOkGK3NLrZ34yTbZX8uJi5sE0NNDYFNflwx1TtnDKkEq+k2DCGfb5w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/additional-methods.min.js"></script>
<title>PoC</title>
</head>
<body class="d-flex flex-column h-100">
<main class="flex-shrink-0">
<div class="container-fluid">
<menu id="navTreeMenu">
<hr />
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#modalAddNav">Add Nav Item</button>
<button id="ajaxSave" type="button" class="btn btn-success btn-sm">Save</button>
<hr />
</menu>
<div class="dd" id="navTree">
<ol class="dd-list">
<li id="navItem1" class="dd-item dd3-item" data-file="file1.php" data-nav="Nav 1" data-page="Page 1" data-id="1">
<div class="dd-handle dd3-handle">Drag</div>
<div class="dd3-content"><div id="entry1">Item 1</div></div>
</li>
</ol>
</div>
<input type="hidden" id="lastID" value="2">
</div>
</main>
<!-- Start: Add Nav Item Modal -->
<form name="frmAddNav" id="frmAddNav" action="" method="post">
<div class="modal fade" id="modalAddNav" tabindex="-1" aria-labelledby="modalAddNavTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header alert-secondary">
<h5 class="modal-title" id="modalAddNavTitle">Add Navigation Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-row my-1">
<div class="col">
<input type="text" name="formPage" id="formPage" class="form-control" placeholder="Page Title">
<div id="formPageError" class="d-flex justify-content-start">
<label id="formPage-error" class="error text-dark flex-fill bg-warning mt-1 rounded" for="formPage"></label>
</div>
</div>
</div>
</div>
<div class="modal-footer text-right alert-secondary">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
<input type="submit" name="btnAddNav" id="btnAddNav" class="btn btn-primary btn-sm" value="Add New">
</div>
</div>
</div>
</div>
</form>
<!-- End: Add Nav Item Modal -->
这里有一个 jsfiddle 显示了这种行为。
我哪里错了?
您的代码中的问题是每次出现模式时,您都会向其添加另一个点击事件。您只需要将点击事件移到 $("#modalAddNav").on('shown.bs.modal'...
.
之外
// Enable drag and drop nest structure
$('#navTree').nestable({ maxDepth: 2 }).on();
// Last ID of current nav tree - needed to add new nav items - passed from server side as hidden input value
var lastID = $('#lastID').val();
console.log('Start ID: ' + lastID);
// jQuery Validator - Validation Settings for AddNav form
var validatorAddNav = $("#frmAddNav").validate(
{
rules:
{
formPage:
{
required: true,
letterswithbasicpunc: true,
rangelength: [3, 20]
}
},
errorPlacement: function (error, element) {
errorInsert = "#" + element.attr("name") + "Error";
error.appendTo(errorInsert);
},
highlight: function (element) { $(element).addClass("is-invalid").removeClass("is-valid"); },
unhighlight: function (element) { $(element).addClass("is-valid").removeClass("is-invalid"); }
});
// AddNav Modal Activated
$("#modalAddNav").on('shown.bs.modal', function () {
console.log('AddNav Modal Shown');
// Set AddNav form focus
$(this).find('#formPage').focus();
});
$('#btnAddNav').click(function (e) {
e.preventDefault(); // Prevent default POST submit
if ($("#frmAddNav").valid()) {
var newID = ++lastID;
var newPage = $('#formPage').val();
console.log('Add Button on ID: ' + newID);
var newLI =
'<li id="navItem' + newID + '" class="dd-item dd3-item" data-file="file' + newID + '.php" data-nav="Nav ' + newID + '" data-page="Page ' + newID + '" data-id="' + newID + '">' +
' <div class="dd-handle dd3-handle">Drag</div>' +
' <div class="dd3-content"><div id="entry1">' + newPage + ' ' + newID + '</div></div>' +
'</li>';
$('#modalAddNav').modal('hide'); // Close Modal
validatorAddNav.resetForm();
$('#navTree > .dd-list').append(newLI); // Add Nav Item to Tree
};
});
// Save Nav Tree - this is where form validation and AJAX will need to go
$('#ajaxSave').click(function (e) {
var navTree = JSON.stringify($('#navTree').nestable('serialize'));
console.log('Nav Tree:\n' + navTree + '\n\n');
});
.dd
{
max-width: 700px;
}
/** Nestable Draggable Handles */
.dd3-content
{
display: block;
height: 30px;
margin: 5px 0;
padding: 5px 10px 5px 40px;
color: #333;
text-decoration: none;
font-weight: bold;
border: 1px solid #ccc;
background: #fafafa;
background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
background: linear-gradient(top, #fafafa 0%, #eee 100%);
-webkit-border-radius: 3px;
border-radius: 3px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
.dd3-content:hover
{
color: #2ea8e5;
background: #fff;
}
.dd-dragel > .dd3-item > .dd3-content
{
margin: 0;
}
.dd3-item > button
{
margin-left: 30px;
}
.dd3-handle
{
position: absolute;
margin: 0;
left: 0;
top: 0;
cursor: pointer;
width: 30px;
text-indent: 30px;
white-space: nowrap;
overflow: hidden;
border: 1px solid #aaa;
background: #ddd;
background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
background: linear-gradient(top, #ddd 0%, #bbb 100%);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.dd3-handle:before
{
content: '≡';
display: block;
position: absolute;
left: 0;
top: 3px;
width: 100%;
text-align: center;
text-indent: 0;
color: #fff;
font-size: 20px;
font-weight: normal;
}
.dd3-handle:hover
{
background: #ddd;
}
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha512-aOG0c6nPNzGk+5zjwyJaoRUgCdOrfSDhmMID2u4+OIslr0GjpLKo7Xm0Ao3xmpM4T8AmIouRkqwj1nrdVsLKEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.css" integrity="sha512-yOW3WV01iPnrQrlHYlpnfVooIAQl/hujmnCmiM3+u8F/6cCgA3BdFjqQfu8XaOtPilD/yYBJR3Io4PO8QUQKWA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Include JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.js" integrity="sha512-7bS2beHr26eBtIOb/82sgllyFc1qMsDcOOkGK3NLrZ34yTbZX8uJi5sE0NNDYFNflwx1TtnDKkEq+k2DCGfb5w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/additional-methods.min.js"></script>
<title>PoC</title>
</head>
<body class="d-flex flex-column h-100">
<main class="flex-shrink-0">
<div class="container-fluid">
<menu id="navTreeMenu">
<hr />
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#modalAddNav">Add Nav Item</button>
<button id="ajaxSave" type="button" class="btn btn-success btn-sm">Save</button>
<hr />
</menu>
<div class="dd" id="navTree">
<ol class="dd-list">
<li id="navItem1" class="dd-item dd3-item" data-file="file1.php" data-nav="Nav 1" data-page="Page 1" data-id="1">
<div class="dd-handle dd3-handle">Drag</div>
<div class="dd3-content"><div id="entry1">Item 1</div></div>
</li>
</ol>
</div>
<input type="hidden" id="lastID" value="2">
</div>
</main>
<!-- Start: Add Nav Item Modal -->
<form name="frmAddNav" id="frmAddNav" action="" method="post">
<div class="modal fade" id="modalAddNav" tabindex="-1" aria-labelledby="modalAddNavTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header alert-secondary">
<h5 class="modal-title" id="modalAddNavTitle">Add Navigation Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-row my-1">
<div class="col">
<input type="text" name="formPage" id="formPage" class="form-control" placeholder="Page Title">
<div id="formPageError" class="d-flex justify-content-start">
<label id="formPage-error" class="error text-dark flex-fill bg-warning mt-1 rounded" for="formPage"></label>
</div>
</div>
</div>
</div>
<div class="modal-footer text-right alert-secondary">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
<input type="submit" name="btnAddNav" id="btnAddNav" class="btn btn-primary btn-sm" value="Add New">
</div>
</div>
</div>
</div>
</form>
<!-- End: Add Nav Item Modal -->
我正在尝试将项目添加到动态拖放列表(来自 here 的 Nestable 2,我已经很清楚了。
我正在使用 Bootstrap 5 模式来获取输入。也在工作。
现在我在表单输入中添加 jQuery validation。就验证而言,这也有效。
但是,当我添加第二个项目时,我添加了两个新项目。第三次尝试时,我添加了三个项目。
这是我的表单提交代码:
// Enable drag and drop nest structure
$('#navTree').nestable({maxDepth: 2}).on();
// Last ID of current nav tree - needed to add new nav items - passed from server side as hidden input value
var lastID = $('#lastID').val();
console.log('Start ID: ' + lastID);
// jQuery Validator - Validation Settings for AddNav form
var validatorAddNav = $("#frmAddNav").validate(
{
rules:
{
formPage:
{
required: true,
letterswithbasicpunc: true,
rangelength: [3, 20]
}
},
errorPlacement: function(error, element)
{
errorInsert = "#" + element.attr("name") + "Error";
error.appendTo(errorInsert);
},
highlight: function(element){$(element).addClass("is-invalid").removeClass("is-valid");},
unhighlight: function(element){$(element).addClass("is-valid").removeClass("is-invalid");}
});
// AddNav Modal Activated
$("#modalAddNav").on('shown.bs.modal',function()
{
console.log('AddNav Modal Shown');
// Set AddNav form focus
$(this).find('#formPage').focus();
$('#btnAddNav').click(function(e)
{
e.preventDefault(); // Prevent default POST submit
if ($("#frmAddNav").valid())
{
var newID = ++lastID;
var newPage = $('#formPage').val();
console.log('Add Button on ID: ' + newID);
var newLI =
'<li id="navItem' + newID + '" class="dd-item dd3-item" data-file="file' + newID + '.php" data-nav="Nav ' + newID + '" data-page="Page ' + newID + '" data-id="' + newID + '">' +
' <div class="dd-handle dd3-handle">Drag</div>' +
' <div class="dd3-content"><div id="entry1">' + newPage + ' ' + newID + '</div></div>' +
'</li>';
$('#modalAddNav').modal('hide'); // Close Modal
validatorAddNav.resetForm();
$('#navTree > .dd-list').append(newLI); // Add Nav Item to Tree
};
});
});
// Save Nav Tree - this is where form validation and AJAX will need to go
$('#ajaxSave').click(function(e)
{
var navTree = JSON.stringify($('#navTree').nestable('serialize'));
console.log('Nav Tree:\n' + navTree + '\n\n');
});
.dd
{
max-width: 700px;
}
/** Nestable Draggable Handles */
.dd3-content
{
display: block;
height: 30px;
margin: 5px 0;
padding: 5px 10px 5px 40px;
color: #333;
text-decoration: none;
font-weight: bold;
border: 1px solid #ccc;
background: #fafafa;
background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
background: linear-gradient(top, #fafafa 0%, #eee 100%);
-webkit-border-radius: 3px;
border-radius: 3px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
.dd3-content:hover
{
color: #2ea8e5;
background: #fff;
}
.dd-dragel > .dd3-item > .dd3-content
{
margin: 0;
}
.dd3-item > button
{
margin-left: 30px;
}
.dd3-handle
{
position: absolute;
margin: 0;
left: 0;
top: 0;
cursor: pointer;
width: 30px;
text-indent: 30px;
white-space: nowrap;
overflow: hidden;
border: 1px solid #aaa;
background: #ddd;
background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
background: linear-gradient(top, #ddd 0%, #bbb 100%);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.dd3-handle:before
{
content: '≡';
display: block;
position: absolute;
left: 0;
top: 3px;
width: 100%;
text-align: center;
text-indent: 0;
color: #fff;
font-size: 20px;
font-weight: normal;
}
.dd3-handle:hover
{
background: #ddd;
}
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha512-aOG0c6nPNzGk+5zjwyJaoRUgCdOrfSDhmMID2u4+OIslr0GjpLKo7Xm0Ao3xmpM4T8AmIouRkqwj1nrdVsLKEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.css" integrity="sha512-yOW3WV01iPnrQrlHYlpnfVooIAQl/hujmnCmiM3+u8F/6cCgA3BdFjqQfu8XaOtPilD/yYBJR3Io4PO8QUQKWA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Include JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.js" integrity="sha512-7bS2beHr26eBtIOb/82sgllyFc1qMsDcOOkGK3NLrZ34yTbZX8uJi5sE0NNDYFNflwx1TtnDKkEq+k2DCGfb5w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/additional-methods.min.js"></script>
<title>PoC</title>
</head>
<body class="d-flex flex-column h-100">
<main class="flex-shrink-0">
<div class="container-fluid">
<menu id="navTreeMenu">
<hr />
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#modalAddNav">Add Nav Item</button>
<button id="ajaxSave" type="button" class="btn btn-success btn-sm">Save</button>
<hr />
</menu>
<div class="dd" id="navTree">
<ol class="dd-list">
<li id="navItem1" class="dd-item dd3-item" data-file="file1.php" data-nav="Nav 1" data-page="Page 1" data-id="1">
<div class="dd-handle dd3-handle">Drag</div>
<div class="dd3-content"><div id="entry1">Item 1</div></div>
</li>
</ol>
</div>
<input type="hidden" id="lastID" value="2">
</div>
</main>
<!-- Start: Add Nav Item Modal -->
<form name="frmAddNav" id="frmAddNav" action="" method="post">
<div class="modal fade" id="modalAddNav" tabindex="-1" aria-labelledby="modalAddNavTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header alert-secondary">
<h5 class="modal-title" id="modalAddNavTitle">Add Navigation Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-row my-1">
<div class="col">
<input type="text" name="formPage" id="formPage" class="form-control" placeholder="Page Title">
<div id="formPageError" class="d-flex justify-content-start">
<label id="formPage-error" class="error text-dark flex-fill bg-warning mt-1 rounded" for="formPage"></label>
</div>
</div>
</div>
</div>
<div class="modal-footer text-right alert-secondary">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
<input type="submit" name="btnAddNav" id="btnAddNav" class="btn btn-primary btn-sm" value="Add New">
</div>
</div>
</div>
</div>
</form>
<!-- End: Add Nav Item Modal -->
这里有一个 jsfiddle 显示了这种行为。
我哪里错了?
您的代码中的问题是每次出现模式时,您都会向其添加另一个点击事件。您只需要将点击事件移到 $("#modalAddNav").on('shown.bs.modal'...
.
// Enable drag and drop nest structure
$('#navTree').nestable({ maxDepth: 2 }).on();
// Last ID of current nav tree - needed to add new nav items - passed from server side as hidden input value
var lastID = $('#lastID').val();
console.log('Start ID: ' + lastID);
// jQuery Validator - Validation Settings for AddNav form
var validatorAddNav = $("#frmAddNav").validate(
{
rules:
{
formPage:
{
required: true,
letterswithbasicpunc: true,
rangelength: [3, 20]
}
},
errorPlacement: function (error, element) {
errorInsert = "#" + element.attr("name") + "Error";
error.appendTo(errorInsert);
},
highlight: function (element) { $(element).addClass("is-invalid").removeClass("is-valid"); },
unhighlight: function (element) { $(element).addClass("is-valid").removeClass("is-invalid"); }
});
// AddNav Modal Activated
$("#modalAddNav").on('shown.bs.modal', function () {
console.log('AddNav Modal Shown');
// Set AddNav form focus
$(this).find('#formPage').focus();
});
$('#btnAddNav').click(function (e) {
e.preventDefault(); // Prevent default POST submit
if ($("#frmAddNav").valid()) {
var newID = ++lastID;
var newPage = $('#formPage').val();
console.log('Add Button on ID: ' + newID);
var newLI =
'<li id="navItem' + newID + '" class="dd-item dd3-item" data-file="file' + newID + '.php" data-nav="Nav ' + newID + '" data-page="Page ' + newID + '" data-id="' + newID + '">' +
' <div class="dd-handle dd3-handle">Drag</div>' +
' <div class="dd3-content"><div id="entry1">' + newPage + ' ' + newID + '</div></div>' +
'</li>';
$('#modalAddNav').modal('hide'); // Close Modal
validatorAddNav.resetForm();
$('#navTree > .dd-list').append(newLI); // Add Nav Item to Tree
};
});
// Save Nav Tree - this is where form validation and AJAX will need to go
$('#ajaxSave').click(function (e) {
var navTree = JSON.stringify($('#navTree').nestable('serialize'));
console.log('Nav Tree:\n' + navTree + '\n\n');
});
.dd
{
max-width: 700px;
}
/** Nestable Draggable Handles */
.dd3-content
{
display: block;
height: 30px;
margin: 5px 0;
padding: 5px 10px 5px 40px;
color: #333;
text-decoration: none;
font-weight: bold;
border: 1px solid #ccc;
background: #fafafa;
background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%);
background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%);
background: linear-gradient(top, #fafafa 0%, #eee 100%);
-webkit-border-radius: 3px;
border-radius: 3px;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
.dd3-content:hover
{
color: #2ea8e5;
background: #fff;
}
.dd-dragel > .dd3-item > .dd3-content
{
margin: 0;
}
.dd3-item > button
{
margin-left: 30px;
}
.dd3-handle
{
position: absolute;
margin: 0;
left: 0;
top: 0;
cursor: pointer;
width: 30px;
text-indent: 30px;
white-space: nowrap;
overflow: hidden;
border: 1px solid #aaa;
background: #ddd;
background: -webkit-linear-gradient(top, #ddd 0%, #bbb 100%);
background: -moz-linear-gradient(top, #ddd 0%, #bbb 100%);
background: linear-gradient(top, #ddd 0%, #bbb 100%);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.dd3-handle:before
{
content: '≡';
display: block;
position: absolute;
left: 0;
top: 3px;
width: 100%;
text-align: center;
text-indent: 0;
color: #fff;
font-size: 20px;
font-weight: normal;
}
.dd3-handle:hover
{
background: #ddd;
}
<html lang="en" class="h-100">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" integrity="sha512-aOG0c6nPNzGk+5zjwyJaoRUgCdOrfSDhmMID2u4+OIslr0GjpLKo7Xm0Ao3xmpM4T8AmIouRkqwj1nrdVsLKEQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.css" integrity="sha512-yOW3WV01iPnrQrlHYlpnfVooIAQl/hujmnCmiM3+u8F/6cCgA3BdFjqQfu8XaOtPilD/yYBJR3Io4PO8QUQKWA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Include JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js" integrity="sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nestable2/1.6.0/jquery.nestable.min.js" integrity="sha512-7bS2beHr26eBtIOb/82sgllyFc1qMsDcOOkGK3NLrZ34yTbZX8uJi5sE0NNDYFNflwx1TtnDKkEq+k2DCGfb5w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/additional-methods.min.js"></script>
<title>PoC</title>
</head>
<body class="d-flex flex-column h-100">
<main class="flex-shrink-0">
<div class="container-fluid">
<menu id="navTreeMenu">
<hr />
<button type="button" class="btn btn-success btn-sm" data-bs-toggle="modal" data-bs-target="#modalAddNav">Add Nav Item</button>
<button id="ajaxSave" type="button" class="btn btn-success btn-sm">Save</button>
<hr />
</menu>
<div class="dd" id="navTree">
<ol class="dd-list">
<li id="navItem1" class="dd-item dd3-item" data-file="file1.php" data-nav="Nav 1" data-page="Page 1" data-id="1">
<div class="dd-handle dd3-handle">Drag</div>
<div class="dd3-content"><div id="entry1">Item 1</div></div>
</li>
</ol>
</div>
<input type="hidden" id="lastID" value="2">
</div>
</main>
<!-- Start: Add Nav Item Modal -->
<form name="frmAddNav" id="frmAddNav" action="" method="post">
<div class="modal fade" id="modalAddNav" tabindex="-1" aria-labelledby="modalAddNavTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header alert-secondary">
<h5 class="modal-title" id="modalAddNavTitle">Add Navigation Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-row my-1">
<div class="col">
<input type="text" name="formPage" id="formPage" class="form-control" placeholder="Page Title">
<div id="formPageError" class="d-flex justify-content-start">
<label id="formPage-error" class="error text-dark flex-fill bg-warning mt-1 rounded" for="formPage"></label>
</div>
</div>
</div>
</div>
<div class="modal-footer text-right alert-secondary">
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
<input type="submit" name="btnAddNav" id="btnAddNav" class="btn btn-primary btn-sm" value="Add New">
</div>
</div>
</div>
</div>
</form>
<!-- End: Add Nav Item Modal -->