به پروژه ی دوم از سری «پروژه های مدرن جاوا اسکریپت» خوش آمدید. در این پروژه قصد داریم یک نرم افزار محاسبه ی وام ایجاد کنیم که سه فیلد مختلف را از شما می گیرد:
و در ازای آن ها سه مورد دیگر را به شما می دهد:
همچنین اگر اعداد را غیرمرتبط وارد کنید برنامه به شما خطا داده و پیام خطا بعد از سه ثانیه از بین می رود. ظاهر برنامه ی ما بدین شکل است:
ما قصد داریم که در این جلسه ظاهر برنامه (UI) را تکمیل کنیم و برای سریع تر شدن کار از بوت استرپ (Bootstrap) استفاده خواهیم کرد. بنابراین به وب سایت https://getbootstrap.com/ مراجعه کرده و روی get started کلیک کنید:
با کلیک روی این لینک، به صفحه ای برده می شوید که در ابتدا به شما CDN های مختلف بوت استرپ را می دهد اما ما می خواهیم از starter template استفاده کنیم. برای شروع کار یک پوشه (در هر جایی مثل دسکتاپ) به نام Loan Calculator ایجاد کنید. سپس درون این پوشه فایل های index.html و app.js و یک پوشه به نام img ایجاد کنید تا تصویر loading را در آن قرار دهیم. شما باید تصویر loading را از این لینک دانلود کرده و درون این پوشه قرار بدهید. حالا به starter template بروید و کد آن را درون index.html کپی کنید (این کدها تنها وابستگی های بوت استرپ هستند - مواردی مانند CDN ها و...). البته باید تغییرات کمی را در آن ایجاد کنیم:
<!doctype html> <html lang="en"> <head> <title>Hello, world!</title> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous"> </head> <body class="bg-dark"> <div class="container"> <div class="row"> <div class="col-md-6 mx-auto"> <div class="card card-body text-center mt-5"> <h1 class="heading display-5 pb-3">Loan Calculator</h1> <form id="loan-form"> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">$</span> <input type="number" class="form-control" id="amount" placeholder="Loan Amount"> </div> </div> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">%</span> <input type="number" class="form-control" id="interest" placeholder="Interest"> </div> </div> <div class="form-group"> <input type="number" class="form-control" id="years" placeholder="Years To Repay"> </div> <div class="forn-group"> <input type="submit" value="Calculate" class="btn btn-dark btn-block"> </div> </form> <!-- LOADER --> <!-- <div id="loading"> <img src="img/loading.gif" alt=""> </div> --> <!-- RESULTS --> <div id="results" class="pt-4"> <h5>Results</h5> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">Monthly Payment</span> <input type="number" class="form-control" id="monthly-payment" disabled> </div> </div> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">Total Payment</span> <input type="number" class="form-control" id="total-payment" disabled> </div> </div> <div class="form-group"> <div class="input-group"> <span class="input-group-addon">Total Interest</span> <input type="number" class="form-control" id="total-interest" disabled> </div> </div> </div> </div> </div> </div> </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script> <script src="app.js"></script> </body> </html>
ظاهر برنامه برایتان باید چیزی شبیه به شکل زیر باشد:
حالا که UI برنامه تکمیل شده است موقع کدنویسی جاوا اسکریپت است. وارد فایل app.js شوید و مشخصا اولین کاری که می کنیم گوش دادن به دکمه ی Calculate (ثبت فرم) است چرا که این دکمه قرار است فرم ما را submit کند:
// Listen for submit document.getElementById('loan-form').addEventListener('submit', calculateResults);
loan-form در واقع id فرم ما است و در صورت submit شدن تابعی به نام calculateResults را اجرا می کند. بنابراین باید این تابع را تعریف کنیم:
// Calculate Results function calculateResults(e) { e.preventDefault(); }
اولین کاری که برای این تابع انجام داده ایم، جلوگیری از submit شدن فرم است (preventDefault) تا بتوانیم با استفاده از جاوا اسکریپت مقدار مورد نظر خودمان را محاسبه کنیم. در مرحله ی بعد باید تمام متغیرهای UI را تعریف کنیم. منظور من از متغیرهای UI متغیر هایی هستند که به عنصری در HTML اشاره می کنند. اگر یادتان باشد در پروژه ی قبلی نیز این کار را انجام دادیم. بنابراین می گوییم:
// Calculate Results function calculateResults(e) { // UI Vars const amount = document.getElementById('amount'); const interest = document.getElementById('interest'); const years = document.getElementById('years'); const monthlyPayment = document.getElementById('monthly-payment'); const totalPayment = document.getElementById('total-payment'); const totalInterest = document.getElementById('total-interest'); e.preventDefault(); }
شما می توانید با مراجعه به فایل index.html تمام این متغیر ها را چک کرده و بر اساس id پیدایشان کنید. حالا نوبت نوشتن فرمول های محاسبه است. این فرمول های ریاضی برای محاسبه ی سود وام و ... استفاده می شوند و ریاضی محض هستند بنابراین اگر متوجه آن ها نمی شوید زیاد جای نگرانی نیست چرا که ربطی به برنامه نویسی ندارند:
const principal = parseFloat(amount.value); const calculatedInterest = parseFloat(interest.value) / 100 / 12; const calculatedPayments = parseFloat(years.value) * 12;
اولین متغیر principle است که مقدار وارد شده (مقدار وام درخواستی - فیلد Loan Amount) توسط کاربر را می گیرد. توجه داشته باشید که متغیر بالاتر از آن که amount نام داشت به خود فیلد اشاره می کرد نه مقدار تایپ شده درون آن، بنابراین amount.value مقدار وارد شده را به ما می دهد. برای محاسبه ی دقیق وام و سود آن باید مقدار وارد شده را به صورت اعشاری داشته باشیم بنابراین از تابع parseFloat استفاده کرده ایم که اعداد را تبدیل به اعداد اعشاری می کند.
دومین متغیر calculatedInterest است که «درصد سود» وام را دریافت می کند. این درصد توسط کاربر وارد می شود بنابراین فیلد interest را گرفته و مقدار (value) آن را دریافت می کنیم. این مقدار نیز باید به صورت اعشاری باشد بنابراین آن را درون parseFloat قرار داده ایم. در نهایت آن را تقسیم بر 100 و سپس تقسیم بر 12 کرده ایم. این موضوع به کدنویسی ما مربوط نیست بلکه فرمول محاسبه ی سود وام به همین شکل است که یک فرمول ریاضی است.
سومین متغیر calculatedPayments است که تعداد سال های بازپرداخت را مشخص می کند. به طور مثال یک وام 10000 دلاری را اگر با سود x در 10 ماه پرداخت کنیم، ماهانه چقدر باید بپردازیم. فرمول محاسبه ی آن هم به شکلی است که میبینید و از طرف کاربر دریافت می شود.
توجه داشته باشید که هنوز درون تابع calculateResults هستیم. در مرحله ی بعد باید مقدار بازپرداخت ماهیانه را حساب کنیم بنابراین:
// Compute monthly payment const x = Math.pow(1 + calculatedInterest, calculatedPayments); const monthly = (principal * x * calculatedInterest) / (x - 1);
ابتدا متغیر x را تعریف کرده ایم. برای مقدار آن، سود بازپرداخت را به علاوه ی 1 کرده و آن را به توان calculatedPayments (سال های بازپرداخت) میرسانیم. Math.pow پارامتر اول را به عنوان پایه و پارامتر دوم را به عنوان توان قرار می دهد. همانطور که گفتم این ها فرمول های ریاضی برای محاسبه ی وام است و ربطی به برنامه نویسی ندارد. حالا متغیر x را گرفته و مقدار وام را در آن ضرب می کنیم، سپس حاصل را ضربدر سود بازپرداخت می نماییم و نتیجه را بر x-1 تقسیم می کنیم.
حالا باید مطمئن شویم که عدد monthly یک عدد محدود باشد (یعنی تا بی نهایت رقم اعشار نداشته باشد یا مقدارش برابر بی نهایت نشود بلکه مقداری محدود داشته باشد تا بتوانیم روی آن عملیات ریاضی انجام دهیم) چرا که برخی اوقات در جاوا اسکریپت اعداد اعشاری رفتارهای عجیبی از خود نشان داده و تا 10 یا 20 رقم اعشار جلو میروند! برای مطمئن شدن از محدود بودن monthly می توانیم از تابعی به نام isFinite استفاده کنیم:
if (isFinite(monthly)) { monthlyPayment.value = monthly.toFixed(2); totalPayment.value = (monthly * calculatedPayments).toFixed(2); totalInterest.value = ((monthly * calculatedPayments) - principal).toFixed(2); } else { showError('Please check your numbers'); }
بنابراین اگر monthly عددی محدود بود، مقدارش را درون فیلد Monthly Payment (مقدار بازپرداخت ماهانه) قرار می دهیم:
monthlyPayment.value = monthly.toFixed(2);
اما برای آنکه بیشتر از 2 رقم اعشار را نمایش ندهد از تابع toFixed استفاده کرده و به عنوان پارامتر عدد 2 (به معنی تا 2 رقم اعشار) را به آن داده ایم. همچنین برای total payment (مجموع بازپرداخت) باید مبلغ بازپرداخت ماهیانه را در تعداد سال های بازپرداخت ضرب کنیم. باز هم از toFixed برای نمایش حداکثر 2 رقم اعشار استفاده کرده ایم. برای مقدار سوم که محاسبه ی «مبلغ بازپرداختی به عنوان سود کل» است گفته ایم همان پرداخت کل را از principle تفریق کن. باز هم از toFixed استفاده می کنیم.
حالا اگر مقدار monthly عددی محدود نبود (قابل اندازه گیری نبود) در قسمت else قرار می گیریم که یعنی احتمالا کاربر اعداد را به صورت صحیح وارد نکرده است. برای این قسمت تابعی به نام showError قرار داده ایم که باید آن را تعریف کنیم. این تابع پیامی را دریافت می کند که در اینجا Please check your numbers را دریافت کرده است (به معنی «لطفا اعداد وارد شده را چک کنید»).
حالا خارج از تابع calculateResults تابع showError را کدنویسی می کنیم:
// Show Error function showError(error) { // Create a div const errorDiv = document.createElement('div'); // Get elements const card = document.querySelector('.card'); const heading = document.querySelector('.heading'); // Add class errorDiv.className = 'alert alert-danger'; // Create text node and append to div errorDiv.appendChild(document.createTextNode(error)); // Insert error above heading card.insertBefore(errorDiv, heading); // Clear error after 3 seconds setTimeout(clearError, 3000); }
کد بالا را تا حدودی در پروژه ی قبل نیز داشتیم. ابتدا یک div ساخته ایم و کلاس های 'alert alert-danger' را نیز به آن داده ایم تا بوت استرپ خطای ما را قرمز نشان دهد. سپس عنصر card و heading را از DOM گرفته ایم تا به جاوا اسکریپت بگوییم خطای ما را درون card و قبل از heading وارد کن. با استفاده از appendChild متن خطا را به div متصل کرده ایم و در نهایت تابع insertBefore را صدا زده ایم. این تابع روی عنصر پدر صدا زده می شود (card) و دو پارامتر می گیرد: پارامتر اول همان عنصری است که قرار است به صفحه اضافه شود و پارامتر دوم عنصری است که پارامتر اول قبل از آن اضافه خواهد شد.
در نهایت از setTimeout استفاده کرده ایم تا پس از 3 ثانیه (3000 میلی ثانیه) پیام خطا حذف شود چرا که از نظر UX خوب نیست که خطا همیشه باقی بماند. setTimeout بعد از 3 ثانیه تابعی به نام clearError را اجرا می کند که باید آن را تعریف کنیم:
// Clear error function clearError() { document.querySelector('.alert').remove(); }
این تابع نیز بسیار ساده است، فقط باید alert خود را از صفحه remove کنیم. اگر به مرورگر برویم و بدون هیچ مقداری فرم را ثبت کنیم چنین خطایی را مشاهده خواهیم کرد:
و پس از سه ثانیه حذف خواهد شد. در قسمت بعد کدهایمان را تکمیل خواهیم کرد تا علامت loading را نیز نمایش دهیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.