You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/bn/7-bank-project/3-data
Lee Stott 2daab5271b
Update Quiz Link
3 weeks ago
..
README.md Update Quiz Link 3 weeks ago
assignment.md 🌐 Update translations via Co-op Translator 4 weeks ago

README.md

ব্যাংকিং অ্যাপ তৈরি করুন পার্ট ৩: ডেটা সংগ্রহ এবং ব্যবহার করার পদ্ধতি

প্রাক-লেকচার কুইজ

প্রাক-লেকচার কুইজ

ভূমিকা

প্রতিটি ওয়েব অ্যাপ্লিকেশনের কেন্দ্রে থাকে ডেটা। ডেটা বিভিন্ন রূপ নিতে পারে, তবে এর প্রধান উদ্দেশ্য হল ব্যবহারকারীর কাছে তথ্য প্রদর্শন করা। ওয়েব অ্যাপ্লিকেশনগুলি ক্রমশ ইন্টারঅ্যাকটিভ এবং জটিল হয়ে উঠছে, তাই ব্যবহারকারী কীভাবে তথ্য অ্যাক্সেস করে এবং এর সাথে ইন্টারঅ্যাক্ট করে তা এখন ওয়েব ডেভেলপমেন্টের একটি গুরুত্বপূর্ণ অংশ।

এই পাঠে, আমরা দেখব কীভাবে সার্ভার থেকে ডেটা অ্যাসিঙ্ক্রোনাসভাবে সংগ্রহ করা যায় এবং এই ডেটা ব্যবহার করে HTML পুনরায় লোড না করেই ওয়েব পেজে তথ্য প্রদর্শন করা যায়।

পূর্বশর্ত

এই পাঠের জন্য আপনাকে লগইন এবং রেজিস্ট্রেশন ফর্ম অংশটি তৈরি করতে হবে। এছাড়াও আপনাকে Node.js ইনস্টল করতে হবে এবং সার্ভার API চালাতে হবে লোকালভাবে যাতে আপনি অ্যাকাউন্ট ডেটা পেতে পারেন।

আপনি টার্মিনালে এই কমান্ডটি চালিয়ে সার্ভারটি সঠিকভাবে চলছে কিনা পরীক্ষা করতে পারেন:

curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result

AJAX এবং ডেটা সংগ্রহ

প্রথাগত ওয়েব সাইটগুলি ব্যবহারকারী যখন একটি লিঙ্ক নির্বাচন করে বা একটি ফর্ম ব্যবহার করে ডেটা জমা দেয় তখন প্রদর্শিত বিষয়বস্তু আপডেট করে, সম্পূর্ণ HTML পেজ পুনরায় লোড করে। নতুন ডেটা লোড করার প্রতিবার, ওয়েব সার্ভার একটি সম্পূর্ণ নতুন HTML পেজ ফেরত দেয় যা ব্রাউজার দ্বারা প্রক্রিয়াকরণ করতে হয়, বর্তমান ব্যবহারকারীর ক্রিয়াকে বাধাগ্রস্ত করে এবং পুনরায় লোডের সময় ইন্টারঅ্যাকশন সীমিত করে। এই ওয়ার্কফ্লোকে মাল্টি-পেজ অ্যাপ্লিকেশন বা MPA বলা হয়।

মাল্টি-পেজ অ্যাপ্লিকেশনে আপডেট ওয়ার্কফ্লো

যখন ওয়েব অ্যাপ্লিকেশনগুলি আরও জটিল এবং ইন্টারঅ্যাকটিভ হতে শুরু করে, তখন একটি নতুন কৌশল AJAX (Asynchronous JavaScript and XML) উদ্ভূত হয়। এই কৌশলটি ওয়েব অ্যাপগুলিকে জাভাস্ক্রিপ্ট ব্যবহার করে সার্ভার থেকে অ্যাসিঙ্ক্রোনাসভাবে ডেটা পাঠাতে এবং সংগ্রহ করতে দেয়, HTML পেজ পুনরায় লোড না করেই, যা দ্রুত আপডেট এবং মসৃণ ব্যবহারকারীর ইন্টারঅ্যাকশন প্রদান করে। যখন সার্ভার থেকে নতুন ডেটা পাওয়া যায়, তখন বর্তমান HTML পেজটি জাভাস্ক্রিপ্ট ব্যবহার করে DOM API এর মাধ্যমে আপডেট করা যায়। সময়ের সাথে সাথে, এই পদ্ধতিটি এখন সিঙ্গেল-পেজ অ্যাপ্লিকেশন বা SPA নামে পরিচিত হয়েছে।

সিঙ্গেল-পেজ অ্যাপ্লিকেশনে আপডেট ওয়ার্কফ্লো

যখন AJAX প্রথম চালু হয়েছিল, তখন অ্যাসিঙ্ক্রোনাসভাবে ডেটা সংগ্রহ করার জন্য একমাত্র API ছিল XMLHttpRequest। তবে আধুনিক ব্রাউজারগুলি এখন আরও সুবিধাজনক এবং শক্তিশালী Fetch API বাস্তবায়ন করে, যা প্রমিজ ব্যবহার করে এবং JSON ডেটা পরিচালনার জন্য আরও উপযুক্ত।

যদিও সমস্ত আধুনিক ব্রাউজার Fetch API সমর্থন করে, যদি আপনি চান আপনার ওয়েব অ্যাপ্লিকেশন পুরানো বা লিগ্যাসি ব্রাউজারে কাজ করুক, তাহলে প্রথমে caniuse.com এ সামঞ্জস্যতার টেবিল পরীক্ষা করা সবসময়ই ভালো ধারণা।

কাজ

পূর্ববর্তী পাঠে আমরা একটি অ্যাকাউন্ট তৈরি করতে রেজিস্ট্রেশন ফর্ম বাস্তবায়ন করেছি। এখন আমরা একটি বিদ্যমান অ্যাকাউন্ট ব্যবহার করে লগইন করার জন্য কোড যোগ করব এবং এর ডেটা সংগ্রহ করব। app.js ফাইলটি খুলুন এবং একটি নতুন login ফাংশন যোগ করুন:

async function login() {
  const loginForm = document.getElementById('loginForm')
  const user = loginForm.user.value;
}

এখানে আমরা প্রথমে getElementById() ব্যবহার করে ফর্ম এলিমেন্টটি সংগ্রহ করি এবং তারপর loginForm.user.value ব্যবহার করে ইনপুট থেকে ব্যবহারকারীর নাম সংগ্রহ করি। প্রতিটি ফর্ম কন্ট্রোলকে HTML-এ name অ্যাট্রিবিউট ব্যবহার করে ফর্মের একটি প্রপার্টি হিসেবে অ্যাক্সেস করা যায়।

রেজিস্ট্রেশনের জন্য আমরা যা করেছি তার অনুরূপ, আমরা একটি নতুন ফাংশন তৈরি করব যা সার্ভার অনুরোধ সম্পাদন করবে, তবে এইবার অ্যাকাউন্ট ডেটা সংগ্রহ করার জন্য:

async function getAccount(user) {
  try {
    const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user));
    return await response.json();
  } catch (error) {
    return { error: error.message || 'Unknown error' };
  }
}

আমরা fetch API ব্যবহার করে সার্ভার থেকে অ্যাসিঙ্ক্রোনাসভাবে ডেটা সংগ্রহ করি, তবে এইবার আমাদের শুধুমাত্র URL ছাড়া অন্য কোনো অতিরিক্ত প্যারামিটার দরকার নেই, কারণ আমরা শুধুমাত্র ডেটা অনুসন্ধান করছি। ডিফল্টভাবে, fetch একটি GET HTTP অনুরোধ তৈরি করে, যা এখানে আমাদের প্রয়োজন।

encodeURIComponent() একটি ফাংশন যা URL এর জন্য বিশেষ অক্ষর এড়িয়ে যায়। যদি আমরা এই ফাংশনটি না ডাকি এবং সরাসরি user মানটি URL-এ ব্যবহার করি, তাহলে কী সমস্যা হতে পারে?

এখন আমাদের login ফাংশনটি getAccount ব্যবহার করার জন্য আপডেট করা যাক:

async function login() {
  const loginForm = document.getElementById('loginForm')
  const user = loginForm.user.value;
  const data = await getAccount(user);

  if (data.error) {
    return console.log('loginError', data.error);
  }

  account = data;
  navigate('/dashboard');
}

প্রথমে, যেহেতু getAccount একটি অ্যাসিঙ্ক্রোনাস ফাংশন, তাই আমাদের এটি await কীওয়ার্ড দিয়ে মেলাতে হবে যাতে সার্ভার ফলাফলের জন্য অপেক্ষা করা যায়। যেকোনো সার্ভার অনুরোধের মতো, আমাদের ত্রুটি ক্ষেত্রগুলি পরিচালনা করতে হবে। আপাতত আমরা শুধুমাত্র একটি লগ বার্তা যোগ করব ত্রুটি প্রদর্শনের জন্য এবং পরে এটি নিয়ে ফিরে আসব।

তারপর আমাদের কোথাও ডেটা সংরক্ষণ করতে হবে যাতে আমরা পরে এটি ব্যবহার করে ড্যাশবোর্ড তথ্য প্রদর্শন করতে পারি। যেহেতু account ভেরিয়েবলটি এখনও বিদ্যমান নেই, আমরা আমাদের ফাইলের শীর্ষে একটি গ্লোবাল ভেরিয়েবল তৈরি করব:

let account = null;

ব্যবহারকারীর ডেটা একটি ভেরিয়েবলে সংরক্ষণ করার পরে আমরা navigate() ফাংশন ব্যবহার করে লগইন পেজ থেকে ড্যাশবোর্ড এ যেতে পারি।

অবশেষে, আমাদের লগইন ফর্মটি জমা দেওয়া হলে আমাদের login ফাংশনটি কল করতে হবে, HTML পরিবর্তন করে:

<form id="loginForm" action="javascript:login()">

একটি নতুন অ্যাকাউন্ট নিবন্ধন করে এবং একই অ্যাকাউন্ট ব্যবহার করে লগইন করার চেষ্টা করে সবকিছু সঠিকভাবে কাজ করছে কিনা পরীক্ষা করুন।

পরবর্তী অংশে যাওয়ার আগে, আমরা register ফাংশনটি সম্পূর্ণ করতে পারি ফাংশনের শেষে এটি যোগ করে:

account = result;
navigate('/dashboard');

আপনি কি জানেন যে ডিফল্টভাবে, আপনি শুধুমাত্র একই ডোমেইন এবং পোর্ট থেকে সার্ভার API কল করতে পারেন যা আপনি দেখছেন? এটি ব্রাউজার দ্বারা প্রয়োগ করা একটি নিরাপত্তা ব্যবস্থা। কিন্তু আমাদের ওয়েব অ্যাপ localhost:3000 এ চলছে, যেখানে সার্ভার API localhost:5000 এ চলছে, এটি কীভাবে কাজ করছে? Cross-Origin Resource Sharing (CORS) নামক একটি কৌশল ব্যবহার করে, যদি সার্ভার প্রতিক্রিয়ায় বিশেষ হেডার যোগ করে নির্দিষ্ট ডোমেইনের জন্য ব্যতিক্রম অনুমতি দেয়, তাহলে ক্রস-অরিজিন HTTP অনুরোধ করা সম্ভব।

API সম্পর্কে আরও জানুন এই পাঠটি নিয়ে।

HTML আপডেট করে ডেটা প্রদর্শন

এখন আমাদের কাছে ব্যবহারকারীর ডেটা রয়েছে, আমাদের বিদ্যমান HTML আপডেট করতে হবে এটি প্রদর্শন করার জন্য। আমরা ইতিমধ্যে জানি কীভাবে DOM থেকে একটি এলিমেন্ট সংগ্রহ করতে হয়, উদাহরণস্বরূপ document.getElementById() ব্যবহার করে। একটি বেস এলিমেন্ট পাওয়ার পরে, এখানে কিছু API রয়েছে যা আপনি এটি পরিবর্তন করতে বা এর মধ্যে নতুন চাইল্ড এলিমেন্ট যোগ করতে ব্যবহার করতে পারেন:

  • textContent প্রপার্টি ব্যবহার করে আপনি একটি এলিমেন্টের টেক্সট পরিবর্তন করতে পারেন। মনে রাখবেন যে এই মানটি পরিবর্তন করলে এলিমেন্টের সমস্ত চাইল্ড (যদি থাকে) সরিয়ে ফেলা হয় এবং প্রদত্ত টেক্সট দিয়ে প্রতিস্থাপিত হয়। সুতরাং, এটি একটি নির্দিষ্ট এলিমেন্টের সমস্ত চাইল্ড সরিয়ে ফেলার জন্য একটি কার্যকর পদ্ধতি, একটি খালি স্ট্রিং '' বরাদ্দ করে।

  • document.createElement() এবং append() পদ্ধতি ব্যবহার করে আপনি একটি বা একাধিক নতুন চাইল্ড এলিমেন্ট তৈরি এবং সংযুক্ত করতে পারেন।

একটি এলিমেন্টের innerHTML প্রপার্টি ব্যবহার করে এর HTML বিষয়বস্তু পরিবর্তন করাও সম্ভব, তবে এটি এড়িয়ে যাওয়া উচিত কারণ এটি ক্রস-সাইট স্ক্রিপ্টিং (XSS) আক্রমণের জন্য ঝুঁকিপূর্ণ।

কাজ

ড্যাশবোর্ড স্ক্রিনে যাওয়ার আগে, লগইন পেজে আমাদের একটি কাজ করতে হবে। বর্তমানে, আপনি যদি এমন একটি ব্যবহারকারীর নাম দিয়ে লগইন করার চেষ্টা করেন যা বিদ্যমান নয়, একটি বার্তা কনসোলে দেখানো হয়, তবে একজন সাধারণ ব্যবহারকারীর জন্য কিছুই পরিবর্তন হয় না এবং আপনি জানেন না কী ঘটছে।

চলুন লগইন ফর্মে একটি প্লেসহোল্ডার এলিমেন্ট যোগ করি যেখানে প্রয়োজনে একটি ত্রুটি বার্তা প্রদর্শন করা যেতে পারে। একটি ভালো জায়গা হবে লগইন <button> এর ঠিক আগে:

...
<div id="loginError"></div>
<button>Login</button>
...

এই <div> এলিমেন্টটি খালি, যার অর্থ স্ক্রিনে কিছুই প্রদর্শিত হবে না যতক্ষণ না আমরা এতে কিছু বিষয়বস্তু যোগ করি। আমরা এটিকে একটি id দিই যাতে আমরা এটি সহজেই জাভাস্ক্রিপ্ট দিয়ে সংগ্রহ করতে পারি।

app.js ফাইলে ফিরে যান এবং একটি নতুন হেল্পার ফাংশন updateElement তৈরি করুন:

function updateElement(id, text) {
  const element = document.getElementById(id);
  element.textContent = text;
}

এই ফাংশনটি বেশ সহজ: একটি এলিমেন্ট id এবং text দেওয়া হলে, এটি মিলে যাওয়া id সহ DOM এলিমেন্টের টেক্সট বিষয়বস্তু আপডেট করবে। চলুন এই পদ্ধতিটি আগের ত্রুটি বার্তার পরিবর্তে login ফাংশনে ব্যবহার করি:

if (data.error) {
  return updateElement('loginError', data.error);
}

এখন আপনি যদি একটি অবৈধ অ্যাকাউন্ট দিয়ে লগইন করার চেষ্টা করেন, আপনি এরকম কিছু দেখতে পাবেন:

লগইন চলাকালীন প্রদর্শিত ত্রুটি বার্তা দেখানো স্ক্রিনশট

এখন আমাদের একটি ত্রুটি টেক্সট রয়েছে যা দৃশ্যমানভাবে প্রদর্শিত হয়, তবে আপনি যদি এটি একটি স্ক্রিন রিডার দিয়ে চেষ্টা করেন, আপনি লক্ষ্য করবেন যে কিছুই ঘোষণা করা হয় না। একটি পেজে গতিশীলভাবে যোগ করা টেক্সট স্ক্রিন রিডার দ্বারা ঘোষণা করার জন্য, এটি একটি লাইভ রিজিয়ন ব্যবহার করতে হবে। এখানে আমরা একটি নির্দিষ্ট ধরনের লাইভ রিজিয়ন ব্যবহার করব যাকে একটি এলার্ট বলা হয়:

<div id="loginError" role="alert"></div>

register ফাংশনের ত্রুটিগুলির জন্য একই আচরণ বাস্তবায়ন করুন (HTML আপডেট করতে ভুলবেন না)।

ড্যাশবোর্ডে তথ্য প্রদর্শন

আমরা যে কৌশলগুলি দেখেছি সেগুলি ব্যবহার করে, আমরা ড্যাশবোর্ড পেজে অ্যাকাউন্ট তথ্য প্রদর্শন করার দায়িত্বও নেব।

এটি একটি অ্যাকাউন্ট অবজেক্ট যা সার্ভার থেকে প্রাপ্ত হয়:

{
  "user": "test",
  "currency": "$",
  "description": "Test account",
  "balance": 75,
  "transactions": [
    { "id": "1", "date": "2020-10-01", "object": "Pocket money", "amount": 50 },
    { "id": "2", "date": "2020-10-03", "object": "Book", "amount": -10 },
    { "id": "3", "date": "2020-10-04", "object": "Sandwich", "amount": -5 }
  ],
}

নোট: আপনার কাজ সহজ করতে, আপনি পূর্ব-বিদ্যমান test অ্যাকাউন্ট ব্যবহার করতে পারেন যা ইতিমধ্যে ডেটা দিয়ে পূর্ণ।

কাজ

চলুন HTML-এ "Balance" সেকশনটি প্লেসহোল্ডার এলিমেন্ট যোগ করে প্রতিস্থাপন করি:

<section>
  Balance: <span id="balance"></span><span id="currency"></span>
</section>

আমরা অ্যাকাউন্টের বিবরণ প্রদর্শনের জন্য এর ঠিক নিচে একটি নতুন সেকশন যোগ করব:

<h2 id="description"></h2>

যেহেতু অ্যাকাউন্টের বিবরণ এর নিচের বিষয়বস্তুর জন্য একটি শিরোনাম হিসেবে কাজ করে, এটি সেমান্টিকভাবে একটি হেডিং হিসেবে চিহ্নিত করা হয়েছে। হেডিং স্ট্রাকচার কেন গুরুত্বপূর্ণ তা সম্পর্কে আরও জানুন এবং পেজটি সমালোচনামূলকভাবে দেখুন এটি নির্ধারণ করতে যে আর কী কী হেডিং হতে পারে।

এরপর, আমরা app.js এ একটি নতুন ফাংশন তৈরি করব প্লেসহোল্ডার পূরণ করতে:

function updateDashboard() {
  if (!account) {
    return navigate('/login');
  }

  updateElement('description', account.description);
  updateElement('balance', account.balance.toFixed(2));
  updateElement('currency', account.currency);
}

প্রথমে, আমরা যাচাই করি যে আমাদের প্রয়োজনীয় অ্যাকাউন্ট ডেটা রয়েছে কিনা। তারপর আমরা পূর্বে তৈরি করা updateElement() ফাংশন ব্যবহার করে HTML আপডেট করি।

ব্যালেন্স প্রদর্শনকে আরও সুন্দর করতে, আমরা toFixed(2) পদ্ধতি ব্যবহার করি যা মানটি দশমিক বিন্দুর পরে ২ ডিজিট সহ প্রদর্শন করতে বাধ্য করে।

এখন আমাদের updateDashboard() ফাংশনটি প্রতিবার ড্যাশবোর্ড লোড হলে কল করতে হবে। আপনি যদি ইতিমধ্যে পাঠ ১ এর অ্যাসাইনমেন্ট শেষ করে থাকেন তবে এটি সহজ হওয়া উচিত, অন্যথায় আপনি নিম্নলিখিত বাস্তবায়ন ব্যবহার করতে পারেন।

updateRoute() ফাংশনের শেষে এই কোডটি যোগ করুন:

if (typeof route.init === 'function') {
  route.init();
}

এবং রুট সংজ্ঞা আপডেট করুন:

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard', init: updateDashboard }
};

এই পরিবর্তনের সাথে, প্রতিবার ড্যাশবোর্ড পেজ প্রদর্শিত হলে, updateDashboard() ফাংশনটি কল করা হয়। লগইনের পরে, আপনি অ্যাকাউন্ট ব্যালেন্স, মুদ্রা এবং বিবরণ দেখতে সক্ষম হওয়া উচিত।

HTML টেমপ্লেট দিয়ে টেবিল রো ডাইনামিকভাবে তৈরি করুন

প্রথম পাঠে আমরা HTML টেমপ্লেট ব্যবহার করেছি এবং appendChild() পদ্ধতি ব্যবহার করে আমাদের অ্যাপের নেভিগেশন বাস্তবায়ন করেছি। টেমপ্লেটগুলি ছোটও হতে পারে এবং একটি পেজের পুনরাবৃত্ত অংশগুলি ডাইনামিকভাবে পূরণ করতে ব্যবহার করা যেতে পারে।

আমরা HTML টেবিলে লেনদেনের তালিকা প্রদর্শন করতে একই পদ্ধতি ব্যবহার করব।

কাজ

HTML <body> এ একটি নতুন টেমপ্লেট যোগ করুন:

<template id="transaction">
  <tr>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</template>

এই টেমপ্লেটটি একটি একক টেবিল রো উপস্থাপন করে, যেখানে আমরা পূরণ করতে চাই এমন ৩টি কলাম রয়েছে: একটি লেনদেনের তারিখ, বস্তু এবং পরিমাণ

তারপর, ড্যাশবোর্ড টেমপ্লেটের টেবিলের <tbody> এলিমেন্টে এই id প্রপার্টি যোগ করুন যাতে এটি জাভাস্ক্রিপ্ট ব্যবহার করে সহজে খুঁজে পাওয়া যায়:

<tbody id="transactions"></tbody>

আমাদের HTML প্রস্তুত, চলুন জাভাস্ক্রিপ্ট কোডে স্যুইচ করি এবং একটি নতুন ফাংশন createTransactionRow তৈরি করি:

function createTransactionRow(transaction) {
  const template = document.getElementById('transaction');
  const transactionRow = template.content.cloneNode(true);
  const tr = transactionRow.querySelector('tr');
  tr.children[0].textContent = transaction.date;
  tr.children[1].textContent = transaction.object;
  tr.children[2].textContent = transaction.amount.toFixed(2);
  return transactionRow;
}

এই ফাংশনটি ঠিক তার নাম অনুসারে কাজ করে: আমরা পূর্বে তৈরি করা টেমপ্লেট ব্যবহার করে একটি নতুন টেবিল রো তৈরি করি এবং লেনদেনের ডেটা ব্যবহার করে এর বিষয়বস্তু পূরণ করি। আমরা এটি আমাদের updateDashboard() ফাংশনে ব্যবহার করব টেবিলটি পূরণ করতে:

const transactionsRows = document.createDocumentFragment();
for (const transaction of account.transactions) {
  const transactionRow = createTransactionRow(transaction);
  transactionsRows.appendChild(transactionRow);
}
updateElement('transactions', transactionsRows);

এখানে আমরা document.createDocumentFragment() পদ্ধতি ব্যবহার করি যা একটি নতুন DOM ফ্রাগমেন্ট তৈরি করে যার উপর আমরা কাজ করতে পারি, অবশেষে এটি আমাদের HTML টেবিলে সংযুক্ত করার আগে।

এই কোডটি কাজ করার আগে আমাদের এখনও একটি কাজ করতে হবে, কারণ আমাদের updateElement() ফাংশন বর্তমানে শুধুমাত্র টেক্সট বিষয়বস্তু সমর্থন করে যদি আপনি test অ্যাকাউন্ট ব্যবহার করে লগইন করেন, তাহলে এখন ড্যাশবোর্ডে একটি লেনদেন তালিকা দেখতে পাবেন 🎉


🚀 চ্যালেঞ্জ

একসাথে কাজ করে ড্যাশবোর্ড পেজটিকে একটি বাস্তব ব্যাংকিং অ্যাপের মতো দেখানোর চেষ্টা করুন। যদি আপনি ইতিমধ্যেই আপনার অ্যাপটি স্টাইল করে থাকেন, তাহলে মিডিয়া কোয়েরি ব্যবহার করে রেসপন্সিভ ডিজাইন তৈরি করার চেষ্টা করুন, যা ডেস্কটপ এবং মোবাইল ডিভাইসে সুন্দরভাবে কাজ করবে।

এখানে একটি স্টাইল করা ড্যাশবোর্ড পেজের উদাহরণ দেওয়া হলো:

ড্যাশবোর্ড স্টাইল করার পরের উদাহরণের স্ক্রিনশট

লেকচার-পরবর্তী কুইজ

লেকচার-পরবর্তী কুইজ

অ্যাসাইনমেন্ট

আপনার কোড পুনর্গঠন এবং মন্তব্য যোগ করুন

অস্বীকৃতি:
এই নথিটি AI অনুবাদ পরিষেবা Co-op Translator ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসাধ্য সঠিকতা নিশ্চিত করার চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। মূল ভাষায় থাকা নথিটিকে প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যা হলে আমরা দায়বদ্ধ থাকব না।