<asp:Button ID="btnGenerateReport" runat="server"
Text="Generate Report"
CssClass="btn btn-success btn-generate"
resourcekey="GenerateReportButton"
OnClientClick="return openNewWindow();"
OnClick="btnGenerateReport_Click" />
<script type="text/javascript">
function openNewWindow () {
document.forms[0].target = '_blank';
setTimeout(function () { window.document.forms[0].target = ''; }, 0);
}
</script>
<html> <body> <div> Prevent default: <input type="checkbox" id="keydownStop" value="1" /> keydown <input type="checkbox" id="keypressStop" value="1" /> keypress <input type="checkbox" id="keyupStop" value="1" /> keyup </div> Ignore: <input type="checkbox" id="keydownIgnore" value="1" /> keydown <input type="checkbox" id="keypressIgnore" value="1" /> keypress <input type="checkbox" id="keyupIgnore" value="1" /> keyup <div> Focus on the input below and press any key. </div> <div> <input type="text" style=" width: 600px" id="keyInput" /> </div> Log: <div> <textarea id="keyLogger" rows="18" onfocus="this.blur()" style="width: 600px; border: 1px solid black"></textarea> </div> <input type="button" value="Clear" onclick="clearLog()" /> <script type="text/javascript"> document.getElementById('keyInput').onkeydown = keyHandler; document.getElementById('keyInput').onkeyup = keyHandler; document.getElementById('keyInput').onkeypress = keyHandler; document.getElementById('keyInput').focus(); function keyHandler(e) { e = e || window.event; if (document.getElementById(e.type + 'Ignore').checked) return; var evt = e.type; while (evt.length < 10) evt += ' ' + log(evt + ' keyCode=' + e.keyCode + ' which=' + e.which + ' charCode=' + e.charCode + ' char=' + String.fromCharCode(e.keyCode || e.charCode) + (e.shiftKey ? ' +shift' : '') + (e.ctrlKey ? ' +ctrl' : '') + (e.altKey ? ' +alt' : '') + (e.metaKey ? ' +meta' : '')); if (document.getElementById(e.type + 'Stop').checked) { e.preventDefault ? e.preventDefault() : (e.returnValue = false); } } function clearLog() { document.getElementById('keyLogger').value = ''; document.getElementById('keyInput').focus(); } function log(text) { var area = document.getElementById('keyLogger'); area.value += text + '\n'; area.scrollTop = area.scrollHeight; } </script> </body> </html>
<!doctype html>
document.onkeydown = function (e) { e = e || event; console.log(e); }
function getCharacter(event) { if (event.which == null) return String.fromCharCode(event.keyCode); // IE else if (event.which != 0 && event.charCode != 0) return String.fromCharCode(event.which); // All others return null; // special key }
<html> <body> <input id="inputText" type="text" /> <script> document.onkeydown = keyDown; document.onkeypress = keyPress; document.onkeyup = keyUp; function keyDown(e) { var input = document.getElementById('inputText'); input.value = 'keyDown started ...'; input.disabled = true; var j = 0; for (var i = 0; i < 999999999; i++) { j = i - j; } console.log(j); //alert('keyDown'); input.value = 'keyDown finished.'; input.disabled = false; } function keyPress(e) { alert('keyPress'); //console.log('keyPress'); } function keyUp(e) { alert('keyUp'); //console.log('keyUp'); } </script> </body> </html>
<html> <head> <script type="text/javascript"> function process() { var above = 0, below = 0; for (var i = 0; i < 200000; i++) { if (Math.random() * 2 > 1) { above++; } else { below++; } } } function test() { var result1 = document.getElementById('log'); var start = new Date().getTime(); console.log('start'); for (var i = 0; i < 200; i++) { result1.value = 'time=' + (new Date().getTime() - start) + ' [i=' + i + ']'; process(); } result1.value = 'time=' + (new Date().getTime() - start) + ' [done]'; console.log('end'); } window.onload = test; </script> </head> <body> <input id='log' /> </body> </html>
<input onkeydown="return false" /> <input onkeypress="return false" />
document.getElementById('myInputText').onkeypress = function (e) { var char = getCharacter(e || window.event); if (!char) return; // special key this.value += char.toUpperCase(); return false; // برای اینکه کاراکتر اضافی نمایش داده نشود }
e ? e : window.event;
document.getElementById('numberInputText').onkeypress = function (e) { e = e || window.event; var chr = getCharacter(e); if (!isNumeric(chr) && chr !== null) return false; } function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n); } function isNumber(val) { return val !== "NaN" && (+val) + '' === val + '' }
0==false // true 0===false // false, because they are of a different type 1=="1" // true, auto type coercion 1==="1" // false, because they are of a different type
e.ctrlKey && e.keyCode == 'A'.charCodeAt(0)
<html> <body> <div id="dotnettips" style="width: 35px; height: 35px; background-image: url(https://www.dntips.ir/favicon.ico); position: absolute; left: 10px; top: 10px;" tabindex="0"> </div> <script> document.getElementById('dotnettips').onkeydown = function (e) { e = e || event; switch (e.keyCode) { case 37: // left this.style.left = parseInt(this.style.left) - this.offsetWidth + 'px'; return false; case 38: // up this.style.top = parseInt(this.style.top) - this.offsetHeight + 'px'; return false; case 39: // right this.style.left = parseInt(this.style.left) + this.offsetWidth + 'px'; return false; case 40: // down this.style.top = parseInt(this.style.top) + this.offsetHeight + 'px'; return false; } } </script> </body> </html>
<html> <body> <input id="inputText" type="text" /> <div id="divCapsLock" style="color: Red; display: none;">Caps Lock is ON!</div> <script> var capsLock = null; document.onkeypress = keyPress; document.onkeydown = keyDown; function keyDown(e) { e = e || event; capsLock = (e.keyCode == 20 && capsLock !== null) ? !capsLock : capsLock; document.getElementById('divCapsLock').style.display = capsLock ? 'block' : 'none'; } function keyPress(e) { if (capsLock != null) return; e = e || window.event; var charCode = e.charCode || e.keyCode; capsLock = (charCode >= 97 && charCode <= 122 && e.shiftKey) || (charCode >= 65 && charCode <= 90 && !e.shiftKey); document.getElementById('divCapsLock').style.display = capsLock ? 'block' : 'none'; } </script> </body> </html>
<html> <body> <div id='divInput'> <input id="inputText" type="text" /> </div> <script> document.getElementById('inputText').onkeydown = inputKeyDown; document.getElementById('divInput').onkeydown = divKeyDown; document.onkeydown = documentKeyDown; window.onkeydown = windowKeyDown; function divKeyDown(e) { console.log('divKeyDown'); } function inputKeyDown(e) { console.log('inputKeyDown'); } function documentKeyDown(e) { console.log('documentKeyDown'); } function windowKeyDown(e) { console.log('windowKeyDown'); } </script> </body> </html>
<html> <body> <input id="inputText" type="text" /> <div id="divCapsLock" style="color: Red; display: none;">Caps Lock is ON!</div> <script> var capsLock = null; var hasFocus = false; document.onkeyup = keyUp; document.onkeypress = keyPress; document.getElementById('inputText').onfocus = focus; document.getElementById('inputText').onblur = focus; function warnCapsLock() { document.getElementById('divCapsLock').style.display = (capsLock != null && capsLock && hasFocus) ? 'block' : 'none'; } function focus() { hasFocus = !hasFocus; warnCapsLock(); } function keyUp(e) { e = e || event; capsLock = (e.keyCode == 20 && capsLock !== null) ? !capsLock : capsLock; warnCapsLock(); } function keyPress(e) { if (capsLock != null) return; e = e || window.event; var charCode = e.charCode || e.keyCode; capsLock = (charCode >= 97 && charCode <= 122 && e.shiftKey) || (charCode >= 65 && charCode <= 90 && !e.shiftKey); warnCapsLock(); } </script> </body> </html>
window.onblur = function () { capsLock = null; }
var Client = {}; Client.Keyboard = {}; Client.Keyboard.EnableKeyDown = true; Client.Keyboard.EnableKeyUp = false; Client.Keyboard.CurrentKeyEvent = null; window.onkeydown = function (event) { if (!Client.Keyboard.EnableKeyDown) return true; return KeyboardEvents(event); }; window.onkeyup = function (event) { if (!Client.Keyboard.EnableKeyUp) return true; return KeyboardEvents(event); }; function Rise(event) { var e = Client.Keyboard.CurrentKeyEvent; if (event) { var data = { shift: e.shiftKey, ctrl: e.ctrlKey, alt: e.altKey }; if (!event(data)) return false; return event(data); } return true; } function KeyboardEvents(e) { e = e || window.event; Client.Keyboard.CurrentKeyEvent = e; switch (e.keyCode) { case 8: return Rise(Client.Keyboard.Backspace); case 9: return Rise(Client.Keyboard.Tab); case 13: return Rise(Client.Keyboard.Enter); case 16: return Rise(Client.Keyboard.Shift); case 17: return Rise(Client.Keyboard.Ctrl); case 18: return Rise(Client.Keyboard.Alt); case 19: return Rise(Client.Keyboard.Pause); case 20: return Rise(Client.Keyboard.CapsLock); case 27: return Rise(Client.Keyboard.Esc); case 33: return Rise(Client.Keyboard.PageUp); case 34: return Rise(Client.Keyboard.PageDown); case 35: return Rise(Client.Keyboard.End); case 36: return Rise(Client.Keyboard.Home); case 37: return Rise(Client.Keyboard.Left); case 38: return Rise(Client.Keyboard.Up); case 39: return Rise(Client.Keyboard.Right); case 40: return Rise(Client.Keyboard.Down); case 44: return Rise(Client.Keyboard.PrtScr); case 45: return Rise(Client.Keyboard.Insert); case 46: return Rise(Client.Keyboard.Delete); ////////////////////////////////////////////////////////////////////////////////////////////////// case 48: return Rise(Client.Keyboard.Num0); case 49: return Rise(Client.Keyboard.Num1); case 50: return Rise(Client.Keyboard.Num2); case 51: return Rise(Client.Keyboard.Num3); case 52: return Rise(Client.Keyboard.Num4); case 53: return Rise(Client.Keyboard.Num5); case 54: return Rise(Client.Keyboard.Num6); case 55: return Rise(Client.Keyboard.Num7); case 56: return Rise(Client.Keyboard.Num8); case 57: return Rise(Client.Keyboard.Num9); ////////////////////////////////////////////////////////////////////////////////////////////////// case 65: return Rise(Client.Keyboard.A); case 66: return Rise(Client.Keyboard.B); case 67: return Rise(Client.Keyboard.C); case 68: return Rise(Client.Keyboard.D); case 69: return Rise(Client.Keyboard.E); case 70: return Rise(Client.Keyboard.F); case 71: return Rise(Client.Keyboard.G); case 72: return Rise(Client.Keyboard.H); case 73: return Rise(Client.Keyboard.I); case 74: return Rise(Client.Keyboard.J); case 75: return Rise(Client.Keyboard.K); case 76: return Rise(Client.Keyboard.L); case 77: return Rise(Client.Keyboard.M); case 78: return Rise(Client.Keyboard.N); case 79: return Rise(Client.Keyboard.O); case 80: return Rise(Client.Keyboard.P); case 81: return Rise(Client.Keyboard.Q); case 82: return Rise(Client.Keyboard.R); case 83: return Rise(Client.Keyboard.S); case 84: return Rise(Client.Keyboard.T); case 85: return Rise(Client.Keyboard.U); case 86: return Rise(Client.Keyboard.V); case 87: return Rise(Client.Keyboard.W); case 88: return Rise(Client.Keyboard.X); case 89: return Rise(Client.Keyboard.Y); case 90: return Rise(Client.Keyboard.Z); //////////////////////////////////////////////////////////////////////////// case 91: //case 219: // opera return Rise(Client.Keyboard.LeftWindow); case 92: return Rise(Client.Keyboard.RightWindow); case 93: return Rise(Client.Keyboard.ContextMenu); //////////////////////////////////////////////////////////////////////////// case 96: return Rise(Client.Keyboard.NumPad0); case 97: return Rise(Client.Keyboard.NumPad1); case 98: return Rise(Client.Keyboard.NumPad2); case 99: return Rise(Client.Keyboard.NumPad3); case 100: return Rise(Client.Keyboard.NumPad4); case 101: return Rise(Client.Keyboard.NumPad5); case 102: return Rise(Client.Keyboard.NumPad6); case 103: return Rise(Client.Keyboard.NumPad7); case 104: return Rise(Client.Keyboard.NumPad8); case 105: return Rise(Client.Keyboard.NumPad9); //////////////////////////////////////////////////////////////////////////// case 106: return Rise(Client.Keyboard.Multiply); case 107: return Rise(Client.Keyboard.Add); case 109: return Rise(Client.Keyboard.Subtract); case 110: return Rise(Client.Keyboard.DecimalPoint); case 111: return Rise(Client.Keyboard.Divide); //////////////////////////////////////////////////////////////////////////// case 112: return Rise(Client.Keyboard.F1); case 113: return Rise(Client.Keyboard.F2); case 114: return Rise(Client.Keyboard.F3); case 115: return Rise(Client.Keyboard.F4); case 116: return Rise(Client.Keyboard.F5); case 117: return Rise(Client.Keyboard.F6); case 118: return Rise(Client.Keyboard.F7); case 119: return Rise(Client.Keyboard.F8); case 120: return Rise(Client.Keyboard.F9); case 121: return Rise(Client.Keyboard.F10); case 122: return Rise(Client.Keyboard.F11); case 123: return Rise(Client.Keyboard.F12); //////////////////////////////////////////////////////////////////////////// case 144: return Rise(Client.Keyboard.NumLock); case 145: return Rise(Client.Keyboard.ScrollLock); case 186: case 59: // opera & firefox return Rise(Client.Keyboard.SemiColon); case 187: case 61: // opera //case 107: //firefox return Rise(Client.Keyboard.Equal); case 188: return Rise(Client.Keyboard.Camma); case 189: return Rise(Client.Keyboard.Dash); case 190: return Rise(Client.Keyboard.Period); case 191: return Rise(Client.Keyboard.Slash); case 192: return Rise(Client.Keyboard.GraveAccent); case 219: return Rise(Client.Keyboard.OpenBracket); case 220: return Rise(Client.Keyboard.BackSlash); case 221: return Rise(Client.Keyboard.CloseBracket); case 222: return Rise(Client.Keyboard.SingleQuote); } };
// ctrl + s Client.Keyboard.S = function (e) { if (e.ctrl) { // انجام عملیات موردنظر } return true; }
اگر به سایت stackoverflow دقت کنید، اندازه textarea ایی که کاربران امکان ارسال مطلب دارند، قابل تغییر است:
شاید برای شما جالب باشد که بدانید به چه صورتی اینکار را انجام دادهاند. اینکار با استفاده از افزونه TextArea Resizer صورت گرفته است. (دریافت کتابخانه به همراه مثال)
البته حالت عمومیتری نیز توسط jQuery-UI استاندارد پشتیبانی میشود (امکان تغییر اندازه یک المان با قابلیت تغییر اندازه در حالت کلی). برای مثال به صفحهی سادهی ASP.Net زیر دقت بفرمائید:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm5.aspx.cs" Inherits="testWebForms87.WebForm5" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
$("#resizableArea").resizable({
handles: "s"
})
.find("textarea").height("100%").width("100%");
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="resizableArea" style="width:300px; height:200px" >
<asp:TextBox ID="TextBox1" runat="server" TextMode="MultiLine" ></asp:TextBox>
</div>
</form>
</body>
</html>
برای مثال با استفاده از این روش میتوان یک GridView با قابلیت تغییر اندازه ایجاد کرد و امثال آن. یا برای نمونه شاید با مثالهایی که به گرید نمایش داده شده اسکرول بار اضافه میکنند برخورده باشید:
<div id="resizableArea" style="overflow:auto;height:200px;">
My Grid view ...
</div>
<asp:Panel ID="pnlScroll" runat="server" Width="391px" Height="282px" ScrollBars="Vertical">
My Grid view ...
</asp:Panel>
»اگر با #F آشنایی ندارید میتوانید از اینجا شروع کنید.
به صورت کلی برای استفاده گسترده از #F در پروژههای وب نیاز به یک سری templateهای آماده داریم در غیر این صورت کار کمی سخت خواهد شد. به تصویر زیر دقت نمایید:
واضح است که با توجه به تصویر بالا کنترلرها و البته مدلهای app و هر آنچه که سمت سرور به آن نیاز است باید با استفاده از #F پیاده سازی شوند. اما هنگامی که کنترلرها با استفاده از #F نوشته شوند سیستم مسیر یابی نیز تحت تاثیر قرار خواهد گرفت. علاوه بر آن باید فکری برای بخش Bundling و همچنین فیلترهاو... نمود. در نتیجه با توجه به template پروژه مورد نظر بر خلاف حالت پیش فرض #C آن که در قالب یک پروژه ارائه میشود در این جا حداقل به دو پروژه نیاز داریم. خوشبختانه همانند پروژه FSharpX که برای WPF مناسب است برای MVC نیز template آماده موجود است که در ادامه با آن آشنا خواهیم شد.
شروع به کار
ابتدا در VS.Net یک پروژه جدید ایجاد نمایید. از بخش Online Template گزینه FSharp MVC 4 را جستجو کنید.
بعد از انتخاب نام پروژه و کلیک بر روی Ok ( و البته دانلود حدود ده MB اطلاعات) صفحه زیر نمایان میشود. در این قسمت تنظیمات مربوط به انتخاب View Engine و نوع قالب پروژه را وجود دارد. در صورتی که قصد استفاده از Web Api را دارید گزینه Web Api Project را انتخاب کنید در غیر این صورت گزینه Empty Project.
البته از Visual Studio 2012 به بعد این بخش به صورت زیر خواهد بود که قسمت Single Page App به آن اضافه شده است:
بعد از کلیک بر روی Ok یک پروژه بر اساس Template مورد نظر ساخته میشود. همانند تصویر زیر:
بررسی تغییرات
در یک نگاه به راحتی میتوان تغییرات زیر را در پروژه Web تشخیص داد:
»پوشه Controller وجود ندارد؛
»پوشه مدل وجود ندارد؛
»فایل Global.asax دیگر فایلی به نام Global.asax.cs را همراه با خود ندارد.
دلیل اصلی عدم وجود موارد بالا این است که تمام این موارد باید به صورت #F پیاده سازی شوند در نتیجه به پروژه #F ساخته شده منتقل شده اند. فایل Global.asax را باز نمایید. سورس زیر قابل مشاهده است:
<%@ Application Inherits="FsWeb.Global" Language="C#" %> <script Language="C#" RunAt="server">
// Defines the Application_Start method and calls Start in // System.Web.HttpApplication from which Global inherits. protected void Application_Start(Object sender, EventArgs e) { base.Start(); } </script>
حال به بررسی پروژه #F ساخته شده خواهیم پرداخت. در این پروژه یک فایل Global.fs وجود دارد که سورس آن به صورت زیر است:
namespace FsWeb open System open System.Web open System.Web.Mvc open System.Web.Routing type Route = { controller : string action : string id : UrlParameter } type Global() = inherit System.Web.HttpApplication() static member RegisterRoutes(routes:RouteCollection) = routes.IgnoreRoute("{resource}.axd/{*pathInfo}") routes.MapRoute("Default", "{controller}/{action}/{id}", { controller = "Home"; action = "Index" id = UrlParameter.Optional } ) member this.Start() = AreaRegistration.RegisterAllAreas() Global.RegisterRoutes(RouteTable.Routes)
RouteConfig.RegisterRoutes(RouteTable.Routes);
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
//تعریف الکوی مسیر یابی type Route = { controller : string action : string id : UrlParameter } type Global() = inherit System.Web.HttpApplication() static member RegisterRoutes(routes:RouteCollection) = //فراخوانی و انتساب الگوی مسیر یابی به مسیرهای تعریف شده routes.IgnoreRoute("{resource}.axd/{*pathInfo}") routes.MapRoute("Default", "{controller}/{action}/{id}", { controller = "Home"; action = "Index" id = UrlParameter.Optional } )
Global.RegisterRoutes(RouteTable.Routes)
در این پست با Template پروژههای F# MVC 4 اشنا شدیم و از طرفی مشخص شد که برای پیاده سازی این گونه پروژهها حداقل نیاز به دو پروژه داریم. یک پروژه که از نوع #C است ولی در آن فقط View ها و فایل جاوااسکریپتی و البته Css وجود دارد. از طرف دیگر کنترلرها و مدلها و هر چیز دیگر که مربوط به سمت سرور است در قالب یک پروژه #F پیاده سازی میشود.
Vue Lifecycle hooks
new Vue({ el: '#app', data() { return { a: 1 }; }, created: function () { // `this` points to the vm instance console.log('a is: ' + this.a) } });
new Vue({ el: '#app', data() { return { name: 'Sirwan' }; }, beforeCreate: function () { console.log('name is: ' + this.name); console.log(`We don't have access to target element at this point: ${this.$el}`); }, created: function () { // `this` points to the vm instance console.log('name is: ' + this.name); console.log(`We don't have access to target element at this point: ${this.$el}`); } });
beforeMount: function () { console.log(`this.$el doesn't exist yet, but it will soon!`); }, mounted: function () { console.log(this.$el); }
new Vue({ el: '#app', data() { return { name: 'Sirwan', counter: 0 }; }, created: function () { setInterval(() => { this.counter++ }, 1000) }, beforeUpdate: function () { console.log(this.counter); // Logs the counter value every second, before the DOM updates. }, updated: function () { console.log(`new value: ${this.counter}`); } });
new Vue({ el: '#app', data() { return { name: 'Sirwan', counter: 0 }; }, beforeDestroy: function () { }, destroyed() { console.log(this) // There's practically nothing here! } });
بررسی سیستم جدید گرید بوت استرپ 3
چهار اندازه متفاوت سیستم گرید بوت استرپ 3
الف) صفحات نمایش بسیار کوچک یا xs، مانند موبایلها (کمتر از 768 پیکسل)
ب) صفحات نمایش کوچک یا sm مانند تبلتها (بیشتر از 768 پیکسل و کمتر از 992 پیکسل)
ج) صفحات نمایش با اندازه متوسط یا md مانند سیستمهای دسکتاپ (بیشتر از 992 پیکسل و کمتر از 1200 پیکسل)
د) صفحات نمایش با اندازه بزرگ یا lg مانند سیستمهای خاص دسکتاپ (بیشتر از 1200 پیکسل)
نحوه تنظیم این چهار اندازه را در تصویر ذیل مشاهده میکنید:
با کدهای کامل زیر:
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My Website</title> <link href="Content/css/bootstrap-rtl.css" rel="stylesheet"> <link href="Content/css/custom.css" rel="stylesheet"> <style> body { padding: 0 16px; } .container { padding: 0 1em; } h4 { margin-top: 1.5em; } .row { margin-bottom: 1.5em; } .row .row { margin-top: 0.8em; margin-bottom: 0; } [class*="col-"] { padding: 1em 0; background-color: rgba(255,195,13,.3); border: 1px solid rgba(255,195,13,.4); } </style> <!--[if lt IE 9]> <script src="Scripts/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <h1>master example grid</h1> <div class="row"> <div class="col-lg-4 col-md-1 col-sm-5 col-xs-5"> <span class="visible-lg">.col-lg-4</span> <span class="visible-md">.col-md-1</span> <span class="visible-sm">.col-sm-5</span> <span class="visible-xs">.col-xs-5</span> </div> <div class="col-lg-4 col-md-5 col-sm-1 col-xs-6"> <span class="visible-lg">.col-lg-4</span> <span class="visible-md">.col-md-5</span> <span class="visible-sm">.col-sm-1</span> <span class="visible-xs">.col-xs-6</span> </div> <div class="col-lg-4 col-md-6 col-sm-6 col-xs-1"> <span class="visible-lg">.col-lg-4</span> <span class="visible-md">.col-md-6</span> <span class="visible-sm">.col-sm-6</span> <span class="visible-xs">.col-xs-1</span> </div> </div> <!-- end row --> <h2>xs Grid</h2> <div class="row"> <div class="col-xs-5"> <p>.col-xs-5</p> </div> <div class="col-xs-6"> <p>.col-xs-6</p> </div> <div class="col-xs-1"> <p>.col-xs-1</p> </div> </div> <!-- end row --> <h2>sm Grid</h2> <div class="row"> <div class="col-sm-5"> <p>.col-sm-5</p> </div> <div class="col-sm-1"> <p>.col-sm-1</p> </div> <div class="col-sm-6"> <p>.col-sm-6</p> </div> </div> <!-- end row --> <h2>md Grid</h2> <div class="row"> <div class="col-md-1"> <p>.col-md-1</p> </div> <div class="col-md-5"> <p>.col-md-5</p> </div> <div class="col-md-6"> <p>.col-md-6</p> </div> </div> <!-- end row --> <h2>lg Grid</h2> <div class="row"> <div class="col-lg-4"> <p>.col-lg-4</p> </div> <div class="col-lg-4"> <p>.col-lg-4</p> </div> <div class="col-lg-4"> <p>.col-lg-4</p> </div> </div> <!-- end row --> </div> <!-- /container --> <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/bootstrap-rtl.js"></script> </body> </html>
در این حین که عرض مرورگر را تغییر میدهید، به سطر اول، بیش از بقیه توجه کنید. این سطر طوری طراحی شده است که در اندازههای مختلف صفحه، اطلاعات متفاوتی را نمایش میدهد. همچنین سلولهای گریدهای پایین صفحه به صورت عمودی بر روی هم قرار خواهند گرفت.
- در این مثال هر ردیف 12 ستونی، با یک div دارای کلاس row شروع میشود.
- اکنون بر اساس اندازه دستگاهی که قرار است سیستم را مطابق آن طراحی یا بهینه سازی کنیم، میتوان از چهار اندازه یاد شده استفاده کرد. ستونهای col-xs به معنای extra small یا بسیار کوچک هستند. ستونهای دارای کلاس col-sm دارای اندازه کوچک یا small میباشند. ستونهای col-md برای حالت medium devices طراحی شدهاند و col-lg برای حالت large devices و صفحات عریض کاربرد دارند.
بنابراین در بوت استرپ 3 بر اساس اندازه غالب صفحه مرورگر کاربران برنامه میتوان سیستم گرید را بهینه سازی کرد.
- اعدادی که پس از نامهای یاد شده میآیند، جمعشان باید 12 بشود. برای مثال در سطر آخر، سه col-lg-4 داریم و در سطرهای دیگر نیز به همین ترتیب، جمع اعداد ستونها، عدد 12 را تشکیل میدهند.
- اگر نیاز است اطلاعاتی جهت اندازه خاصی نمایش داده شود، مانند سطر اول، از کلاسهایی مانند visible-lg میتوان استفاده کرد.
- style ابتدای مثال نیز صرفا برای رنگی نمایش دادن این سیستم گرید و ارائه توضیحات واضحتری در مورد آن تعریف شدهاند.
نکات تکمیلی سیستم گریدهای بوت استرپ 3
1) ترکیب اندازههای مختلف گریدها با هم
فرض کنید یک ردیف را با چهار ستون col-md-3 طراحی کردهاید. اندازهی صفحه که اندکی کوچکتر شود، تمام این ستونها تبدیل به 4 ردیف خواهند شد و شاید در این حالت بجای داشتن یک سیستم تک ستونی چهار ردیفه، سیستمی 2 ردیفه با 2 ستون، مطلوب کار ما باشد و به این ترتیب قسمت عمدهای از صفحه خالی باقی نماند.
<div class="row"> <div class="col-md-3 col-xs-6"> </div> <div class="col-md-3 col-xs-6"> </div> <div class="col-md-3 col-xs-6"> </div> <div class="col-md-3 col-xs-6"> </div> </div>
در مثال فوق، اگر اندازه صفحه برای حالت md مناسب باشد، 4 ستونه نمایش داده میشود. اگر اندازه اندکی کوچکتر گردد، 2 ستونه میشود؛ بجای تک ستونه صرف حالت col-md.
2) استفاده از div محصور کننده container
<div class="container"> </div>
3) ایجاد فاصله بین ستونها
اگر علاقمند باشید تا بین ستونهای یک گرید فاصله ایجاد کنید، باید از offset استفاده کرد. یک مثال:
<div class="container"> <h4 class="alert alert-info">ایجاد فاصله بین ستونها</h4> <div class="row"> <div class="col-lg-3 col-sm-4"> col-lg-3 col-sm-4 </div> <div class="col-lg-8 col-lg-offset-1 col-sm-7 col-sm-offset-1"> col-lg-8 col-lg-offset-1 col-sm-7 col-sm-offset-1 </div> </div> <!-- end row --> </div> <!-- /container -->
اگر در حالت معمولی، دو ستون با تعاریف col-lg-3 و col-lg-9 تعریف شدهاند، میتوان از ستون دوم یک واحد کم کرد و یک واحد به آفست آن افزود تا از ستون کناری فاصله بگیرد. آفست از سمت چپ ستون عمل میکند و اگر از نسخه RTL استفاده میکنید، از سمت راست.
علت اینکه در اینجا هم از col-lg استفاده شده و هم از col-sm، در قسمت 1 توضیح داده شد. میخواهیم این ردیف حتی در بازه sm نیز دو ستونی نمایش داده شود.
4) تعیین ترتیب ستونها
تعیین ترتیب ستونها نیز یکی دیگر از قابلیتهای جدید گرید بوت استرپ 3 است. مثلا در مثال 3 فوق، با کاهش عرض مرورگر، بالاخره زمانی فرا میرسد که تمام ستونها در قالب یک ردیف نمایش داده خواهند شد. در این حالت اگر ستون سمت راست را منو و ستون سمت چپ را محتوای صفحه فرض کنیم، شاید علاقمند باشیم که بجای اینکه ابتدا منو نمایش داده شود و سپس در ردیف زیرین، محتوای صفحه، این ترتیب معکوس گردد. برای این منظور میتوان از push و pull استفاده کرد:
<div class="container"> <h4 class="alert alert-info">تغییر ترتیب ستونها در اندازههای مختلف صفحه</h4> <div class="row"> <div class="col-lg-offset-1 col-sm-offset-1 col-lg-8 col-sm-7 col-lg-push-3 col-sm-push-4"> col-lg-offset-1 col-sm-offset-1 col-lg-8 col-sm-7 col-lg-push-3 col-sm-push-4 </div> <div class="col-lg-3 col-sm-4 col-lg-pull-9 col-sm-pull-8"> col-lg-3 col-sm-4 col-lg-pull-9 col-sm-pull-8 </div> </div> <!-- end row --> </div> <!-- /container -->
در اینجا در div اول به ازای هر کدام از حالتهای sm و lg مدنظر، یک push اضافه شده است و در div دوم یک pull.
push سبب میشود تا div اول به سمت راست صفحه هدایت گردد و pull باعث خواهد شد تا div دوم به سمت چپ رانده شود (برای آزمایش این مساله یکبار push مربوط به div اول را حذف کنید و نتیجه را در مروگر بررسی کنید و سپس یکبار pull اضافه شده به div دوم را به صورت موقت حذف نمائید).
5) ایجاد ردیفهای تو در تو
یکی از امکانات پیش فرض گریدهای بوت استرپ، امکان قرار دادن کل محتوای یک ردیف داخل ردیف یا ستونی دیگر است. برای مثال محتوایی در ستون دوم نمایش داده میشود و قصد داریم دقیقا در ذیل آن یک ردیف 4 ستونه داشته باشیم. در این حالت تنها کافی است این ردیف را داخل ستون دوم ایجاد کنیم.
6) قابلیتی به نام جامبوترون!
حتما بسیاری از سایتها را دیدهاید که در ابتدای صفحه اول خود، قسمت عمدهای را در بالای صفحه به نمایش یک عکس بزرگ با چند سطر متن داخل آن اختصاص دادهاند. به این کار در بوت استرپ، جامبوترون میگویند. برای تدارک آن نیز باید از یک ردیف 12 ستونی کامل بدون ستون استفاده کرد. یعنی فقط یک row باید ذکر شود. اما بجای row میتوان از کلاس مخصوص دیگری استفاده کرد:
<div class="container"> <h4 class="alert alert-info">جامبوترون!</h4> <div class="jumbotron"> jumbotron <br> jumbotron <br> jumbotron <br> </div> <!-- end row --> </div> <!-- /container -->
در اینجا اگر تصویری را نیز قرار دادید، با استفاده از کلاسهای pull-left یا pull-right میتوان موقعیت تصویر را نیز تغییر داد.
فایلهای نهایی این قسمت را از اینجا نیز میتوانید دریافت کنید:
bs3-sample02.zip
jQuery Tips #1
کد زیر را در نظر بگیرید
$(function () { // اندازه واقعی فونت var originalFontSize = $('#test').css('font-size'); $(".resetFont").click(function () { $('#test').css('font-size', originalFontSize); }); // افزایش اندازه فونت $(".increaseFont").click(function () { var currentFontSize = $('#test').css('font-size'); var currentFontSizeNum = parseFloat(currentFontSize); var newFontSize = currentFontSizeNum + 5; $('#test').css('font-size', newFontSize); return false; }); // کاهش اندازه فونت $(".decreaseFont").click(function () { var currentFontSize = $('#test').css('font-size'); var currentFontSizeNum = parseFloat(currentFontSize); var newFontSize = currentFontSizeNum - 5; $('#test').css('font-size', newFontSize); return false; }); });
و کد HTML زیر را
<div id="test"> jQuery Tips By Mohsen Bahrzadeh </div> <a href="#">decreaseFont</a> <a href="#">Increase</a> <a href="#">resetFont</a>
برای این کار ابتدا اندازه جاری تگ را گرفته و درون متغیر currentFontSize قرار داده سپس مقدار متغیر currentFontSize را به Float تبدیل کرده و 5 واحد به آن اضافه کرده ایم و سپس عدد بدست آمده را به عنوان اندازه فونت جدید در نظر گرفته ایم. برای متد سوم دقیقاً همین اتفاق میافتد فقط به جای + از - استفاده شده است
در این آموزش قصد دارم نحوه ایجاد یک Slideshow به صورت داینامیک را با ASP.NET طراحی کنم(منظور از ایجاد Slideshow به صورت داینامیک این است که عکسها را به صورت داینامیک از DB بخواند).
اولین گام این است که Plugin مورد نظر را دریافت کنید که من از پلاگین Orbit استفاده کرده ام
ابتدا یک DataBase با نام DynamicSlideShow ایجاد و یک جدول با ساختار زیر با نام Picturesدرون آن ایجاد میکنیم
گام بعدی ایجاد یک پروژه Asp.Net با زبان C# و اضافه کردن فایلهای پلاگین به پروژه و ایجاد یک Handler برای بازیابی دادهها از DB است. ساختار Solutionما باید به صورت زیر باشد
برای اینکه بتوانیم با DB ارتباط برقرار کنیم از EF استفاده میکنیم به همین منظور ابتدا یک Model به نام DynamicSlideShowModel ایجاد میکنیم
در گام بعد بر روی GenerateFromDatabase انتخاب کرده و بر روی دکمه Next کلیک میکنیم و در مراحل بعد ابتدا DB مربوط به مثال (DynamicSlideShow) و جدول آن را انتخاب میکنیم . حال یک Model به درون پوشه App_Code اضافه شده استدر ادامه برای واکشی رکوردهای موجود در جدول Pictures کدهای زیر را درون Handler مینویسیم
var ctx = new DynamicSlideShowEntities(); var list = ctx.Pictures.ToList(); string str = JsonConvert.SerializeObject(list); context.Response.Write(str);
در این کدها تنها نکتهای که احتیاج به توضیح دارد این است که ابتدا یک لیست از
رکوردها را از جدول Pictures
واکشی میکنیم و برای پاس دادن به کلاینت ما آنها را به فرمت Json تبدیل کرده ایم که برای تبدبل از
کنابخانه آماده Newtonsoft.Json.dll
استفاده کرده ایم
حال باید با استفاده از jQuery کدهای درون Handler را اجرا کنیم؛ برای همین منظور یک صفحه با نام default.aspx ایجاد کرده و کدهای زیر را درون آن مینویسیم
<head runat="server"> <title>Dynamic SlideShow</title> <link href="CSS/orbit-1.2.3.css" rel="stylesheet" type="text/css" /> <script src="Script/jquery-1.7.1.min.js" type="text/javascript"></script> <script src="Script/jquery.orbit-1.2.3.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { $.ajax({ url: "Handler.ashx", contentType: "application/json; charset=utf-8", success: function (data) { $.each(data, function (i, b) { var str = '<img src="' + b.PicturePath + '" alt="' + b.PictureText + '"/>'; $("#featured").append(str); }); $('#featured').orbit(); }, dataType: "json" }); }); </script> </head> <body> <form id="form1" runat="server"> <div id="featured"> </div> </form> </body>
در اینجا ابتدا با استفاده از متد ajax کتابخانه jQuery کدهای درون Handler را اجرا کرده و به ازای هر المان موجود در جدول یک تگ img به صفحه اضافه میکنیم.
دریافت و نصب افزونهی SQL Server مخصوص VSCode
برای افزودن این افزونه، ابتدا در برگهی Extensions، عبارت mssql را جستجو کرده و سپس آنرا نصب کنید:
پس از نصب آن، مرحلهی بعد، ایجاد یک فایل خالی با پسوند sql است.
انجام اینکار ضروری است و شبیه به حالت نصب افزونهی #C میباشد. به این ترتیب وابستگیهای اصلی آن دریافت، نصب و فعال خواهند شد. این ابزارها نیز سورس باز بوده و موتور SQL Formatter، اجرای SQL و Intellisense آنرا فراهم میکند و چون مبتنی بر NET Core. تهیه شدهاست، چندسکویی است.
تا اینجا مزیتی را که به دست خواهیم آورد Syntax highlighting و Intellisense جهت درج واژههای کلیدی عبارات SQL است:
و یا اگر بر روی فایل sql جاری کلیک راست کنیم، گزینهی Format Document آن سبب میشود تا کدهای SQL نوشته شده، با فرمتی استاندارد، مرتب و یکدست شوند:
بنابراین اگر علاقمندید تا فایلها و عبارات SQL خود را فرمت کنید، این افزونهی سبک وزن چندسکویی، یک چنین قابلیت توکاری را به همراه دارد.
همچنین اگر علاقمندید به یک کتابخانهی سورس باز چندسکویی SQL Formatter و SQL Parser دات نتی دسترسی داشته باشید، کدهای Microsoft/sqltoolsservice در دسترس هستند.
اتصال به SQL Server و کار با آن
پس از نصب مقدماتی افزونهی mssql، دکمههای ctrl+shift+p (و یا F1) را فشرده و عبارت sql را جستجو کنید:
در اینجا سایر قابلیتهای این افزونهی نصب شده را میتوان مشاهده کرد. در لیست ظاهر شده، گزینهی Connect را انتخاب کنید. بلافاصله گزینهی انتخاب پروفایل ظاهر میشود. چون هنوز پروفایلی را تعریف نکردهایم، گزینهی Create connection profile را انتخاب خواهیم کرد:
در ادامه باید نام سرور را وارد کرد. یا میتوانید نام سرور کامل SQL خود را وارد کنید و یا اگر با LocalDB کار میکنید نیز امکان اتصال به آن با تایپlocaldb\MSSQLLocalDB وجود دارد:
سپس نام بانک اطلاعاتی را که میخواهیم به آن متصل شویم ذکر میکنیم:
در مرحلهی بعد، باید نوع اعتبارسنجی اتصال مشخص شود:
چون در ویندوز هستیم، میتوان گزینهی Integrated را نیز انتخاب کرد (یا همان Windows Authentication).
در آخر، جهت تکمیل کار و دخیرهی این اطلاعات وارد شده، میتوان نام پروفایل دلخواهی را وارد کرد:
اکنون کار اتصال به این بانک اطلاعاتی انجام شده و اگر به status bar دقت کنید، نمایش میدهد که در حال به روز رسانی اطلاعات intellisense است.
برای نمونه اینبار دیگر intellisense ظاهر شده منحصر به درج واژههای کلیدی SQL نیست. بلکه شامل تمام اشیاء بانک اطلاعاتی که به آن متصل شدهایم نیز میباشد:
در ادامه برای اجرا این کوئری میتوان دکمههای Ctrl+Shift+E را فشرد و یا ctrl+shift+p (و یا F1) را فشرده و در منوی ظاهر شده، گزینهی execute query را انتخاب کنید (این گزینه بر روی منوی کلیک راست ظاهر شدهی بر روی فایل sql جاری نیز قرار دارد):
نگاهی به محل ذخیره سازی اطلاعات اتصال به بانک اطلاعاتی
پروفایلی را که در قسمت قبل ایجاد کردیم، در منوی File->Preferences->Settings قابل مشاهده است:
// Place your settings in this file to overwrite the default settings { "workbench.colorTheme": "Default Light+", "files.autoSave": "afterDelay", "typescript.check.tscVersion": false, "terminal.integrated.shell.windows": "cmd.exe", "workbench.iconTheme": "material-icon-theme", "vsicons.dontShowNewVersionMessage": true, "mssql.connections": [ { "server": "(localdb)\\MSSQLLocalDB", "database": "TestASPNETCoreIdentityDb", "authenticationType": "Integrated", "profileName": "testLocalDB", "password": "" } ] }
برای مثال پروفایلی را که تعریف کردیم، در دفعات بعدی انتخاب گزینهی Connect، به صورت ذیل ظاهر میشود:
تهیهی خروجی از کوئری اجرا شده
اگر به نوار ابزار سمت راست نتیجهی کوئری اجرا شده دقت کنید، سه دکمهی تهیهی خروجی با فرمتهای csv، json و اکسل نیز در اینجا قرار داده شدهاست:
برای مثال اگر گزینهی json آنرا انتخاب کنید، بلافاصله نام فایلی را پرسیده و سپس این نتیجه را با فرمت JSON نمایش میدهد:
ضمن اینکه حتی میتوان سطرها و سلولهای خاصی را نیز از این خروجی انتخاب کرد و سپس با کلیک بر روی آنها، تنها از این انتخاب، یک خروجی ویژه را تهیه نمود:
مشاهدهی ساختار اشیاء
اگر بر روی هر کدام از اجزای یک کوئری SQL متصل به بانک اطلاعاتی، کلیک راست کنیم، گزینهی Go to definition نیز ظاهر میشود:
با انتخاب آن، بلافاصله عبارت کامل CREATE TABLE [dbo].[AppRoles] ظاهر میشود که در اینجا میتوان ساختار این جدول را به صورت یک عبارت SQL مشاهده کرد.
تغییر تنظیمات افزونهی MSSql
در منوی File->Preferences->Settings با جستجوی mssql میتوان تنظیمات پیش فرض این افزونه را یافت. برای مثال اگر میخواهید تا SQL Formatter آن به صورت خودکار تمام واژههای کلیدی را با حروف بزرگ نمایش دهد، گزینهی mssql.format.keywordCasing را انتخاب کنید. در کنار آن آیکن قلم ویرایش ظاهر میشود. با کلیک بر روی آن، منوی انتخاب uppercase را خواهیم داشت:
پس از این تغییر، اکنون بر روی صفحه کلیک راست کرده و گزینهی Format Document را انتخاب کنید. در این حالت علاوه بر تغییر فرمت سند SQL جاری، تمام واژههای کلیدی آن نیز uppercase خواهند شد.
مرور مثال این قسمت
تا اینجا در مثالی که بررسی کردیم، لیست اتاقها توسط کامپوننت IndividualRoom.razor و لیست خدمات رفاهی یک هتل توسط کامپوننت IndividualAmenity.razor در کامپوننت والد DemoHotel.razor، نمایش داده شدهاند:
دکمههای حذف و ویرایش هر اتاق نیز در کامپوننت EditDeleteButton.razor قرار دارند که توسط کامپوننت IndividualRoom.razor مورد استفاده قرار میگیرند.
اکنون میخواهیم با کلیک بر روی دکمهی حذف کامپوننت EditDeleteButton، یک modal بوت استرپی جهت دریافت تائیدیهی عملیات، نمایش داده شود و در صورت تائید آن، اتاق انتخابی از لیست اتاقهای کامپوننت DemoHotel حذف گردد.
بنابراین در ابتدا کامپوننت EditDeleteButton، به کامپوننت IndividualRoom خبر درخواست حذف یک اتاق را میدهد. سپس کامپوننت IndividualRoom، یک مودال دریافت تائیدیهی حذف را نمایش میدهد. پس از تائید حذف توسط کاربر، این رویداد به کامپوننت DemoHotel، جهت حذف اتاق انتخابی از لیست اتاقها، اطلاع رسانی خواهد شد.
ایجاد کامپوننت مودال دریافت تائید
در ابتدا، فایل جدید Pages\LearnBlazor\LearnBlazorComponents\Confirmation.razor را ایجاد کرده و به صورت زیر تکمیل میکنیم:
@if (ShowModal) { <div class="modal-backdrop show"></div> <div class="modal fade show" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true" style="display: block;"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title"> @Title </h5> <button @onclick="OnCancelClicked" type="button" class="close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> @ChildContent </div> <div class="modal-footer"> <button @onclick="OnCancelClicked" type="button" class="btn btn-secondary">@CancelButtonLabel</button> <button @onclick="OnConfirmClicked" type="button" class="btn btn-primary">@OkButtonLabel</button> </div> </div> </div> </div> } @code { private bool ShowModal; [Parameter] public string Title { get; set; } = "Confirm"; [Parameter] public string CancelButtonLabel { get; set; } = "Cancel"; [Parameter] public string OkButtonLabel { get; set; } = "Ok"; [Parameter] public RenderFragment ChildContent { get; set; } [Parameter] public EventCallback OnConfirm { get; set; } [Parameter] public EventCallback OnCancel { get; set; } public void Show() => ShowModal = true; public void Hide() => ShowModal = false; private async Task OnConfirmClicked() { ShowModal = false; await OnConfirm.InvokeAsync(); } private async Task OnCancelClicked() { ShowModal = false; await OnCancel.InvokeAsync(); } }
- در اینجا در ابتدا تگها و کلاسهای مرتبط با نمایش یک modal استاندارد بوت استرپی را مشاهده میکنید.
- اگر فیلد خصوصی ShowModal به false تنظیم شود، چون کل محتوای این کامپوننت از DOM حذف خواهد شد (اثر if@ تعریف شده)، سبب مخفی شدن و عدم نمایش آن میگردد.
- این کامپوننت عنوان و برچسبهای دکمههای خودش را به صورت پارامتر دریافت میکند.
- برای اینکه بتوان محتوای نمایشی این کامپوننت را پویا کرد، از یک RenderFragment استفاده کردهایم:
[Parameter] public RenderFragment ChildContent { get; set; }
- همچنین میخواهیم به کامپوننت فراخوان این امکان را بدهیم تا بتواند به صورت مستقل، سبب نمایش یا مخفی شدن وهلهای از این کامپوننت شود. به همین جهت دو متد عمومی Show و Hide نیز تعریف شدهاند.
هدایت درخواست Delete به کامپوننت نمایش مشخصات اتاق
با توجه به اینکه دکمههای حذف و ویرایش هر اتاق، در کامپوننت Pages\LearnBlazor\LearnBlazorComponents\EditDeleteButton.razor قرار دارند، به آن مراجعه کرده و امکان انتشار این رخداد را به فراخوان آن، با تعریف رویداد OnDelete میدهیم:
@if (IsAdmin) { <input type="button" class="btn btn-danger" value="Delete" @onclick="OnDelete" /> <input type="button" class="btn btn-success" value="Edit" /> } @code { [Parameter] public bool IsAdmin { get; set; } [Parameter] public EventCallback OnDelete { get; set; } }
کامپوننت Pages\LearnBlazor\LearnBlazorComponents\IndividualRoom.razor که نمایش دهندهی جزئیات هر اتاق است، با مدیریت رویداد OnDelete کامپوننت EditDeleteButton، از درخواست حذف اتاق جاری مطلع میشود:
<EditDeleteButton IsAdmin="true" OnDelete="OnDeleteClicked"></EditDeleteButton> <Confirmation @ref="Confirmation1" OnCancel="OnCancelClicked" OnConfirm="@(() => OnDeleteSelectedRoom.InvokeAsync(Room))"> <div> Do you want to delete `@Room.Name`? </div> </Confirmation>
- سپس نیاز است زمانیکه OnDelete کامپوننت EditDeleteButton رخداد، این modal دریافت تائید را نمایش دهیم. به همین جهت باید بتوانیم متد عمومی Show آنرا فراخوانی کنیم. بنابراین از ref@ برای دسترسی به وهلهای از این کامپوننت تعریف شده استفاده کردهایم تا توسط شیء Confirmation1، بتوانیم متد عمومی Show را در رویدادگردان منتسب به OnDelete فراخوانی کنیم.
- همچنین دو رویداد OnCancel و OnConfirm کامپوننت دریافت تائید را به متد خصوصی OnCancelClicked و رویداد جدید OnDeleteSelectedRoom متصل کردهایم. یعنی زمانیکه کاربر بر روی دکمهی OK مودال ظاهر شده کلیک میکند، Room جاری، از طریق رویداد OnDeleteSelectedRoom به فراخوان کامپوننت IndividualRoom ارسال میشود تا دقیقا بداند که چه اتاقی را بایدحذف کند:
@code { Confirmation Confirmation1; [Parameter] public BlazorRoom Room { get; set; } [Parameter] public EventCallback<BlazorRoom> OnDeleteSelectedRoom { get; set; } void OnDeleteClicked() { Confirmation1.Show(); } void OnCancelClicked() { // Confirmation1.Hide(); } // ... }
حذف اتاق انتخابی در کامپوننت نمایش لیست اتاقها
مرحلهی آخر این مثال، بسیار سادهاست. در حلقهای که هر اتاق را توسط کامپوننت IndividualRoom نمایش میدهد، به رویداد OnDeleteSelectedRoom گوش فرا داده و selectedRoom یا همان BlazorRoom ارسالی را، دریافت و از لیست Rooms کامپوننت جاری حذف میکنیم. این حذف شدن، بلافاصله سبب رندر مجدد UI و حذف آن از رابط کاربری نیز خواهد شد:
@foreach (var room in Rooms) { <IndividualRoom OnRoomCheckBoxSelection="RoomSelectionCounterChanged" Room="room" OnDeleteSelectedRoom="@(selectedRoom => Rooms.Remove(selectedRoom))"> </IndividualRoom> }
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-12.zip