আপনি এই গল্পটি আগে শুনেছেন। আপনার ইতিমধ্যে একটি অ্যাপ্লিকেশন আছে যা ডিসেন্ট্রালাইজড এবং ফুলি-ওয়ার্কিং ব্যাক-এন্ড API-র ওপর চলছে এবং ফ্রন্ট-এন্ড لأي সাধারণ টুলসেট দিয়ে তৈরি।
এখন, আপনি Angular-এ যেতে চান। অথবা, হয়তো আপনি শুধু আপনার রেইলস প্রজেক্টের সাথে Angular ইন্টিগ্রেট করার একটি উপায় খুঁজছেন কারণ আপনি এই পথটি পছন্দ করেন। আমরা আপনাকে ব্লেম করি না।
এই পদ্ধতিতে, আপনি উভয় জগতের সুবিধা নিতে পারেন এবং تصمیم নিতে পারেন আপনি রেইলস বা Angular-এর ফিচার ব্যবহার করতে চান কিনা, উদাহরণস্বরূপ স্টাফ ফরম্যাট করার জন্য।
আমরা কী বিল্ড করব
চিন্তা করার কিছু নেই। এই টিউটোরিয়াল এই উদ্দেশ্যে লিখা হয়েছে। আমরা ইউজার ডোমেনের ওপর একটি ফুলি-ওয়ার্কিং CRUD অ্যাপ্লিকেশন তৈরিতে ডুব দিব।
আর্টিকেলের শেষে, আপনি Angular-এর কিছু বেসিক কনসেপ্ট এবং কীভাবে একটি রেইলস ব্যাক-এন্ড প্রজেক্ট সেট আপ করতে হয় যা সরাসরি Angular-কে ফ্রন্ট-এন্ডের জন্য ইন্টিগ্রেট করে, সেটা শিখে যাবেন, নিচের মতো:
Rails এবং Angular দিয়ে তৈরি ইউজার CRUD
অ্যাপ্লিকেশনটি ইউজার ডোমেনের ওপর সব চারটি CRUD অপারেশন হ্যান্ডল করবে যা একটি এক্সটারনাল ফেক-টেস্টিং ওয়েব সার্ভিস থেকে রিট্রিভ করা হবে। অ্যাপটি MVC আর্কিটেকচারের ওপর তৈরি হবে, প্রতিটি Angular লেイヤার বিস্তারিত ব্যাখ্যা করা থাকবে যাতে আপনি ভালোভাবে বুঝতে পারেন কীভাবে সবকিছু একসাথে কাজ করে। স্টাইলিংর জন্য Bootstrap ব্যবহার করা হবে।
সেটআপ
আপনি অনুমান করতে পারেন, আমাদের নিচের সফটওয়্যারগুলো লাগবে:
- Ruby (আমি 2.7.0preview1 ভার্সন বেছে নিয়েছি),
- Rails (আমি 5.0.7.2 ভার্সন ব্যবহার করছি),
- Node.js (আমি v13.7.0 ব্যবহার করছি),
- Yarn (কমপক্ষে 1.22.4 ভার্সন)
সবকিছু ঠিকমতো ইনস্টল করা হয়েছে কিনা নিশ্চিত করুন। তারপর প্রজেক্টে যান। আপনার পছন্দের ফোল্ডার সিলেক্ট করুন এবং নিচের কমান্ড চালান:
rails new crud-rails-angular
সেটআপ কমপ্লিট হওয়ার জন্য অপেক্ষা করুন এবং আপনার পছন্দের IDE-তে প্রজেক্ট খুলুন। আমরা এই আর্টিকেলের জন্য VS Code ব্যবহার করব কারণ এটি সিম্পল, পাওয়ারফুল, এবং রেইলস ও Angular সিনট্যাক্স দুটোই স্মুথলি হ্যান্ডেল করে।
যদি আপনি কিছুক্ষণ ধরে Rails 5 ব্যবহার করছেন, তবে আপনি লক্ষ্য করতে পারেন এর new কমান্ড Gemfile-এ SQLite কনফিগারেশনের জন্য একটি বাগ জেনারেট করে। এতে মিনিমাম ভার্সন থাকে না, এবং তাই এরর সহ চলে। আসুন এটি ফিক্স করি আপডেট করে:
gem 'sqlite3', '~> 1.3.10'
পারফেক্ট!
Webpacker সেটআপ
Rails-এ JavaScript-লাইক অ্যাপ্লিকেশন ম্যানেজ করার সেরা উপায় হল Webpacker। এটি পিছনে Webpack ব্যবহার করে JavaScript অ্যাপ্লিকেশন (যেমন Angular) প্রি-প্রসেসিং এবং বান্ডলিং-র মতো ফিচার প্রদান করে একটি বিদ্যমান রেইলস অ্যাপ্লিকেশনে।
ইনস্টল করতে, আপনার Gemfile-এ একটি নতুন লাইন যোগ করুন:
gem 'webpacker', '~> 4.3.x'
এটি নিশ্চিত করবে যে আপনি একটি খুব gầnের ভার্সন ইনস্টল করছেন। এরপর নিচের কমান্ডগুলো চালান:
bundle install
bundle exec rake webpacker:install
bundle exec rake webpacker:install:angular
প্রথম কমান্ডটি যোগ করা রেইলস ডিপেন্ডেন্সি ডাউনলোড এবং আপডেট করবে।
দ্বিতীয় কমান্ডটি npm install-এর সমতুল্য যেহেতু এটি node_modules ফোল্ডার তৈরি করে এবং কিছু প্রয়োজনীয় Angular ডিপেন্ডেন্সি ইনস্টল করে, যেমন Babel, Sass, Browserlist, এবং Webpack। এখন আমাদের একই প্রজেক্টে Node এবং রেইলস অ্যাপ উভয়ই আছে।
তৃতীয় কমান্ডে, আমাদের npm install angular-এর সমতুল্য রয়েছে, যা সকল Angular-প্রয়োজনীয় ডিপেন্ডেন্সি ডাউনলোড করবে এবং আমাদের রেইলস প্রজেক্টের সাথে কাজ করাবে।
এই কমান্ডগুলো শেষে, আপনি package.json ফাইলটি তৈরি হয়ে দেখতে পাবেন। আমাদের সব প্রয়োজনীয় ডিপেন্ডেন্সি সেখানে থাকবে, এবং ভবিষ্যতে আপনি যা চান তা যোগ করতে পারবেন।
এছাড়াও, /app ফোল্ডারের অধীনে কিছু ফোল্ডার এবং ফাইল তৈরি হয়েছে, যেমন নতুন /javascript। এই ফোল্ডারে, আপনার ইতিমধ্যে একটি /hello_angular ফোল্ডার আছে যা আপনার ডেভেলপমেন্ট শুরু করার জন্য সহায়তা করবে।
সময় বাঁচাতে, আমি আপনাকে অনুরোধ করছি আপনার ফোল্ডার এবং ফাইল স্ট্রাকচার নিচের মতো মিরর করুন:

কিছু Angular অ্যাডজাস্টমেন্ট
Webpacker আপনার জেনারেট করা রেইলস প্রজেক্টে কিছু অ্যাডজাস্টমেন্ট সুপারিশ করে। তাই, আসুন ঘরটা একটু আয়োজন করি।
প্রথমে, /packs ফোল্ডারের অধীনে রাখা application.js ফাইলটি খুলুন (উপরের ফিগারে দেখানো হয়েছে) এবং নিচের কোড যোগ করুন:
import "core-js/stable";
import "regenerator-runtime/runtime";
এই ইমপোর্টগুলো রেইলস প্রজেক্টের মধ্যে JavaScript এনভায়রনমেন্ট স্ট্যাবিলাইজ করার জন্য সহায়ক বলের মত কাজ করে।
এখন, আমাদের রেইলসকে জানাতে হবে সে আউটপুট কোথা থেকে নেবে তার পেজগুলোতে। একবার Webpacker প্যাকিং ফিনিশ করলে, এটি একসাথে অনেক ডিস্ট্রিবিউটেবল স্ট্যাটিক ফাইল জেনারেট করবে যা রেইলসকে জানতে হবে।
app/views/layout ফোল্ডারের অধীনে application.html.erb ফাইলটি যান এবং এর <head> ট্যাগের কন্টেন্ট নিচের মতো পরিবর্তন করুন:
<head>
<title>CrudRailsAngular</title>
<base href="/" /> <!-- 1 -->
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" /> <!-- 2 -->
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application' %> <!-- 3 -->
</head>
এটি একটু ব্রেক ডাউন করি:
- এখানে, আমরা
baseট্যাগ যোগ করছি, যা রেইলসে বলে দেয় অ্যাপ্লিকেশন শুরু হলে কোথা তাকাতে হবে। - আমরা পেজে স্টাইল দিতে Bootstrap ব্যবহার করব, যাতে আমরা শুধু ইমপ্লিমেন্টেশনে ফোকাস করতে পারি।
- এখানে আপনাকে Webpacker ট্যাগটি রাখতে হবে যা /packs ফোল্ডারের কন্টেন্টে ম্যাপ করে (সেটি যা Webpacker প্রতিটি কম্পাইলেশনের পর অটো-জেনারেট করবে)।
মডেল এবং ডাটাবেস
ডাটাবেস সেটআপে যান। জিনিসগুলো দ্রুত করার জন্য, আমরা User নামে একটি নতুন মডেল স্ক্যাফোল্ড করব। এটি কমান্ডটি:
rails g scaffold User name:string age:integer address:text && rake db:migrate
এটি আমাদের মডেলের সকল ফোল্ডার এবং ফাইল তৈরি করবে, যা রেইলসকে ডাটাবেস ইনফরমেশন ম্যানিপুলেট করতে (SQLite থেকে) এবং আমাদের CRUD অপারেশনগুলোর জন্য স্টোর করতে সাহায্য করবে।
তারপর, আপনি দেখবেন db/migrate/ ফোল্ডারের অধীনে একটি নতুন ফাইল XXX1_create_users.rb তৈরি হয়েছে। এটিকে খুলুন, এবং আপনি নতুন তৈরি CreateUsers রেকর্ড দেখবেন।
app/models/ ফোল্ডারের মধ্যে, আপনি তখন তৈরি User মডেলটি user.rb ফাইলে পাবেন।
এখন, db/seeds.rb ফাইলটি খুলুন এবং নিচের কোড যোগ করুন:
User.create(name: 'Luke Wan', age: 23, address: '123 Test St.')
User.create(name: 'Mary Poppins', age: 41, address: '123 ABC St.')
User.create(name: 'John Neilman', age: 76, address: '000 Test St.')
এই কোডটি স্টার্টআপে আমাদের Users টেবিলকে কিছু ডেটা দিয়ে ইনিশিয়ালাইজ করবে। সেভ করুন, এবং কমান্ড চালান:
rake db:seed
এটি উপরের কমান্ডগুলো দিয়ে টেবিলকে সিড করবে। এরপর, আপনি SQLite ডাটাবেসে ঢুকে চেক করতে পারেন যে এটি কাজ করেছে কিনা কমান্ড দিয়ে:
sqlite3 db/development.sqlite3
তারপর, টেবিল ডেটা সিলেক্ট করুন:
select * from users;
আপনি রেজাল্ট দেখতে পাবেন।
User কম্পোনেন্ট
আপনাকে আরও কিছু ডিপেন্ডেন্সি ইনস্টল করতে হবে HTML এবং CSS কনভার্ট করতে রেইলস পেজগুলোতে; Angular রাউটার, ফর্ম লাইব্রেরি, এবং ngx-bootstrap অ্যাড করব, যা আমরা Bootstrap কম্পোনেন্ট তৈরি এবং ম্যানিপুলেট করতে ব্যবহার করব। তাই নিচের কমান্ড ইস্যু করুন:
yarn add @angular/router @angular/forms html-loader css-loader ngx-bootstrap
তবে, কম্পোনেন্ট কোডে ঝাঁপ দেওয়ার আগে, কিছু গুরুত্বপূর্ণ কনসেপ্ট জানতে হবে, শুরু করে Angular কম্পোনেন্টের Анатমি।
কম্পোনেন্ট কী?
Angular-এ, একটি কম্পোনেন্ট আপনার ভিউগুলোর সাথে অ্যাপ্লিকেশন লজিক (TypeScript-এ তৈরি) কানেক্ট করার জন্য існу করে।
অন্য কথায়, একটি কম্পোনেন্ট হলো একটি কন্টেইনার যা আপনার ভিউগুলোর ফাংশনিং সাপোর্ট করার জন্য সমস্ত লজিক ধারণ করে। এটি ডিফাইন করে যে ভিউগুলো কী মান উপস্থাপন করবে এবং তাদের ফ্লো কন্ট্রোল করে। এটি অন্য ফ্রেমওয়ার্কের 'কন্ট্রোলার'-এর সমতুল্য।
একটি কম্পোনেন্ট তৈরি করতে, আপনাকে শুধু একটি নতুন ক্লাস ডিফাইন করতে হবে, OnInit ইন্টারফেস ইমপ্লিমেন্ট করতে হবে, এবং ক্লাসকে @Component ডেকোরেটর দিয়ে এনটেট করতে হবে:
export class UserIndexComponent implements OnInit {
constructor() { ... }
ngOnInit() { ... }
}
@Component এবং OnInit
@Component ডেকোরেটর গুরুত্বপূর্ণ কারণ এটি এই ক্লাসকে একটি রিকগনাইজেবল Angular কম্পোনেন্ট চিহ্নিত করে এবং মেটাডেটা কনফিগারেশন প্রদান করে যা Angular-কে প্রসেসিং, ইনস্ট্যানশিয়েশন, এবং রানটাইমে ব্যবহার করার ক্ষেত্রে সাহায্য করে।
নিচের মেটাডেটা কনফিগারেশনগুলো নিন:
@Component({
selector: "users",
template: templateString,
})
এখানে, selector Angular-কে বলে যে প্রদত্ত মান হল CSS সিলেক্টর যা এটি ব্যবহার করতে পারে করেন্ট ডিরেক্টিভকে একটি টেমপ্লেটে আইডেন্টিফাই করার জন্য; হ্যাঁ, এটি একই টেমপ্লেট যা পরবর্তী মেটাডেটা প্রোপার্টিতে দেওয়া আছে।
OnInit ইন্টারফেস, তবে, অপশনাল, এবং কম্পোনেন্ট তার লাইফসাইকেল ফিনিশ করার আগে জিনিসগুলো ইনিশিয়ালাইজ করার একটি ভালো উপায়। এটি পোস্ট-কনস্ট্রাক্ট মেথডের মত কাজ করে।
ডিপেন্ডেন্সি ইনজেকশন
Angular একটি DI (Dependency Injection) ফ্রেমওয়ার্ক, একটি বৈশিষ্ট্য যা এর মডুলারিটি এবং প্রোডাক্টিভিটি বাড়ায়।
Angular-এ ডিপেন্ডেন্সি হতে পারে আপনার সার্ভিস এবং রিপোজিটরি থেকে যেকোনো সাধারণ অবজেক্ট যা আপনি মনে করেন কোডের কোথাও ইনজেক্ট করার উপযোগী।
একটি ক্লাসকে "ইনজেক্টেবল" বানাতে, আপনাকে শুধু এটিকে @Injectable ডেকোরেটর দিয়ে এনটেট করতে হবে:
@Injectable({
providedIn: "root",
})
export class UserService { ... }
providedIn ইন্ডিকেট করে কোন ইনজেক্টর আপনার তৈরি ইনজেক্টেবলটি প্রদান করবে। root মান Angular-কে বলে যে ইনজেক্টরটি অ্যাপ্লিকেশন-লেভেল वाला হওয়া উচিত। আরও আছে যা আপনি এখানে চেক করতে পারেন।
একটি কম্পোনেন্টে ক্লাস ইনজেক্ট করতে, উদাহরণস্বরূপ, আপনি Angular-কে কম্পোনেন্টের কনস্ট্রাক্টরে করতে বলেন:
constructor(
private userService: UserService,
) {}
এটা এতটাই সহজ!
সম্পূর্ণ কম্পোনেন্ট
নিচে, আপনি আমাদের User কম্পোনেন্টের ফাইনাল কোড লিস্টিং পাবেন। এটিকে index.component.ts-এ রাখুন, javascript/hello_angular/app/ ফোল্ডারের অধীনে।
import { Component, OnInit, TemplateRef } from "@angular/core";
import { FormGroup, FormBuilder } from "@angular/forms";
import { BsModalRef, BsModalService } from "ngx-bootstrap/modal";
import templateString from "./index.component.html";
import { UserService } from "../user.service";
import { User } from "../user.class";
@Component({
selector: "users",
template: templateString,
})
export class UserIndexComponent implements OnInit {
users: User[];
modalRef: BsModalRef;
userForm: FormGroup;
isNew: Boolean;
constructor(public fb: FormBuilder, private userService: UserService, private modalService: BsModalService) {}
public newUser(template: TemplateRef<any>) {
this.reset();
this.modalRef = this.modalService.show(template);
}
public createUser() {
this.userService.create(this.userForm.value).subscribe(() => {
console.log("User created!");
this.reset();
this.modalRef.hide();
});
}
public editUser(user, template: TemplateRef<any>) {
this.isNew = false;
this.userForm = this.fb.group({
id: [user.id],
name: [user.name],
age: [user.age],
address: [user.address],
});
this.modalRef = this.modalService.show(template);
}
public updateUser() {
const { id } = this.userForm.value;
this.userService.update(id, this.userForm.value).subscribe(() => {
console.log("User updated!");
this.reset();
this.modalRef.hide();
});
}
public deleteUser(id) {
if (confirm("Are you sure?")) {
this.userService.delete(id).subscribe(() => {
console.log("User deleted!");
this.reset();
});
}
}
ngOnInit() {
this.reset();
}
public reset() {
this.isNew = true;
this.userService.getUsers().subscribe((users) => {
this.users = users;
});
this.userForm = this.fb.group({
id: [""],
name: [""],
age: [""],
address: [""],
});
}
}
users অ্যারে করেন্ট টেবিল ডেটা ধারণ করবে যা স্ক্রিনে লিস্টেড থাকে এবং reset মেথড থেকে রিট্রিভ করা হয়, যা পরিবর্তে আমাদের রেইলস API-কে UserService মাধ্যমে কল করে (যেটি তৈরি করা হবে)।
userForm শুধু একটি রেফারেন্স যা ইউজার তৈরি এবং আপডেট করতে সাহায্য করে যেহেতু একই ফর্ম দুটি অপারেশনের জন্য ব্যবহার হবে। isNewও এতে সাহায্য করে, চিহ্নিত করে যে আমরা বর্তমানে কোন ফ্লোতে আছি।
এখানে, আমাদের প্রতিটি অপারেশনের জন্য CRUD-সমতুল্য মেথড আছে। প্রতিটি সংশ্লিষ্ট UserService মেথড কল করে রেইলস API-তে প্রসেস কমিট করতে।
আমাদের HTML মডিউলও সেট আপ করতে হবে আমাদের টেমপ্লেটগুলো HTML-এ কনভার্ট করার জন্য (মডিউলসम्बন্ধে শীঘ্রই আরও দেখব)। তাই, একই ফোল্ডারের ভিতরে html.d.ts ফাইলটি খুলুন এবং যোগ করুন:
declare module "*.html" {
const content: string;
export default content;
}
Angular সার্ভিস এবং মডেল
চলুন Angular-এর UserService তৈরিতে যাই। Angular একটি ফ্রেমওয়ার্ক, ঠিক রেইলসের মত। তাই, তাদের নিয়ম মেনে চলা ঠিক, এমনকি এতে ডুপ্লিকেট (বা খুব সাদৃশ্য) মডেল থাকলেও।
মডেল কী?
Angular মডেলগুলো সিম্পল অবজেক্ট যা ডেটা অ্যাট্রিবিউট ধারণ করে যা একসাথে অর্থ বহন করে (অর্থাৎ, তারা আপনার ডোমেনের একটি সংক্ষিপ্ত টুকরো রিপ্রেজেন্ট করে)। তারা অধিকাংশ ভাষা এবং ফ্রেমওয়ার্কের মতো যেকোনো অন্য মডেলের মত।
আপনার ডেটা এক জায়গা কনসেন্ট্রেটেড রাখা খুব সাহায্য করে, বরং কোড জুড়ে ডুপ্লিকেট করার পরিবর্তে যেমন আমরা ইউজারের মডেলের সাথে করি:
export class User {
constructor(public id: number, public name: string, public age: number, public address: string) {}
}
মনে রাখবেন এটি TypeScript, তাই আপনার মডেলের অ্যাট্রিবিউটগুলোর সবসময় একটি টাইপ ডিফাইন করা থাকতে হবে।
user.class.ts নামে একটি নতুন ফাইল তৈরি করুন javascript/hello_angular/app/user/ ফোল্ডারের অধীনে এবং উপরের কোডটি সেখানে রাখুন।
সার্ভিস কী?
সার্ভিস একটি বিস্তৃত কনসেপ্ট, কিন্তু আমরা এটিকে ভালো-ডিফাইনড এবং পারপাসফুল অবজেক্ট হিসেবে বুঝতে পারি। তারা কম্পোনেন্টগুলোর সাথে আরও জটিল লজিকের জন্য সাহায্য করে, সেগুলোকে প্রসেসড এবং ট্রান্সফর্মড ডেটা দিয়ে সার্ভ করে, সাধারণত একটি এক্সটারনাল সার্ভিস বা ডাটাবেস থেকে আসা।
একটি সার্ভিসে কোনো স্পেসিফিক এনটেশন বা ইন্টারফেস লাগে না; আপনি শুধু একটি ক্লাস তৈরি করুন এবং এটাকে ইনজেক্টেবল বানান, যেন আমরা দেখেছি। তারপর, আপনি এটিকে আপনার কম্পোনেন্টগুলোর মধ্যে ইনজেক্ট করতে পারেন।
অবজার্ভেবল সার্ভিস
Angular-এর আর একটি আকর্ষণীয় বৈশিষ্ট্য হলো এটি আপনাকে আপনার ক্লাসের সাথে RxJS ব্যবহার করার অনুমতি দেয়।
উদাহরণস্বরূপ, Angular-এর ডিফল্ট HTTP ক্লায়েন্ট, একই যেটি আমরা এক্সটারনাল সার্ভিস থেকে ইনফরমেশন ফেচ করতে ব্যবহার করব, RxJS Observables রিটার্ন করে। এটাই কারণ, যখন আপনি আমাদের UserService মেথডগুলোর যেকোনো একটা কম্পোনেন্টের ভিতরে কল করেন, আপনি subscribe করতে পারেন Observable রেজাল্টে:
this.userService.getUsers().subscribe((users) => {
this.users = users;
});
নোট: আপনি যদি RxJS-এ পরিচিত না হন, আমি দৃঢ়ভাবে রিকমেন্ড করব এর ডকুমেন্টেশনের ওপর একটি সংক্ষিপ্ত রিড; এটি उतনো হার্ড নয়! ;)
আবার, javascript/hello_angular/app/user/ ফোল্ডারে, আরেকটি ফাইল তৈরি করুন user.service.ts নামে। এর কন্টেন্ট:
import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { map } from "rxjs/operators";
import { Observable } from "rxjs";
import { User } from "./user.class";
@Injectable({
providedIn: "root",
})
export class UserService {
constructor(private http: HttpClient) {}
httpOptions = {
headers: new HttpHeaders({
"Content-Type": "application/json",
}),
};
getUsers(): Observable<User[]> {
return this.http.get("/users.json").pipe(
map((users: User[]) => users.map((user) => {
return new User(user.id, user.name, user.age, user.address);
}))
);
}
create(user): Observable<User> {
return this.http.post<User>("/users.json", JSON.stringify(user), this.httpOptions);
}
update(id, user): Observable<User> {
return this.http.put<User>("/users/" + id + ".json", JSON.stringify(user), this.httpOptions);
}
delete(id) {
return this.http.delete<User>("/users/" + id + ".json", this.httpOptions);
}
}
আপনি কি কম্পোনেন্টের সাথে সাদৃশ্য খুঁজে পাচ্ছেন? এটি হলো কারণ আমাদের কম্পোনেন্টের অপারেশনগুলো সাপোর্ট করার জন্য করেসপন্ডিং অপারেশন चाहिए।
নোট করুন HttpClient-ও ক্লাসের কনস্ট্রাক্টরে ইনজেক্ট করা উচিত, যাতে আমরা ক্লাসের পাশাপাশি এটি ব্যবহার করতে পারি।
প্রতিটি অপারেশন আমাদের রেইলস API-তে একটি HTTP কল করে, অটো-জেনারেটেড वाला।
ভিউস
Angular ভিউসের জন্য টেমপ্লেট নিয়ে কাজ করে। একটি টেমপ্লেট হলো একটি সর্ট অফ হায়ারার্কিক্যাল HTML-এন্ড-JavaScript মিক্স যা Angular-কে বলে কীভাবে প্রতিটি কম্পোনেন্ট রেন্ডার করবে।
তবে, আমাদের ভিউ কনস্ট্রাকশন আরও এগিয়ে যাওয়ার আগে, আসুন প্রথমে বুঝি Angular কীভাবে তার টেমপ্লেট সিস্টেম স্প্লিট করে।
Angular ডিরেক্টিভস
কারণ Angular টেমপ্লেটগুলো এসেনশিয়ালি ডাইনামিক, কিছু ডিরেক্টিভ লাগে Angular কে সঠিক পথে চালানোর জন্য স্টাফ রেন্ডার করার জন্য।
ডিরেক্টিভগুলো সিম্পলি ক্লাস जिनতে @Directive ডেকোরেটর থাকে, কম্পোনেন্টের মত। হ্যাঁ, @Component @Directive-র থেকে ইনহেরিট করে, তাই এটি অফিশিয়ালি একটি ডিরেক্টিভ ও।
তবে, দুটি অন্য টাইপ আছে: স্ট্রাকচারাল এবং অ্যাট্রিবিউট ডিরেক্টিভ।
স্ট্রাকচারাল ডিরেক্টিভস
এই ডিরেক্টিভগুলো কন্ডিশনাল এবং লুপ স্ট্রাকচার রিপ্রেজেন্ট করে যা JavaScript থেকে Angular টেমপ্লেটে ট্রান্সলেট করা হয়েছে। তারা টেমপ্লেটকে যতটা সম্ভব ডাইনামিক বানায়, যেন আপনি আপনার ভ্যানিলা JavaScript কোডে প্রোগ্রামিং করছেন। নিচের উদাহরণটি নিন:
<tr *ngFor="let user of users">
<td>{{ user.name }}</td>
</tr>
*ngFor ডিরেক্টিভ Angular-কে বলে users অ্যারেের ওপর ইটারেট করতে এবং প্রতিটি ইউজারের নাম DOM-এ প্রিন্ট করতে।
অ্যাট্রিবিউট ডিরেক্টিভস
এগুলো এলিমেন্টের আপিয়ারেন্স বা বিহেভিয়রের সাথে সরাসরি কাজ করে। নিচের উদাহরণটি নিন:
<form [formGroup]="userForm" (ngSubmit)="isNew ? createUser() : updateUser()" novalidate></form>
এখানে, আমরা ফর্মের বিহেভিয়র মডিফাই করছি এর submit ফাংশন কন্ডিশনালি সেট করে এবং Angular-এর FormGroup ব্যবহার করে ফর্ম ইনপুটগুলোর প্রতিটিকে ডেটা-বাইন্ড করছি।
ডেটা বাইন্ডিং
ওয়েব ফ্রেমওয়ার্কে ফর্ম তৈরি করা ট্রिकी এবং এরর-প্রোন কাজ হতে পারে যদি এটি ডেটা বাইন্ডিং প্রদান না করে।
Angular টু-ওয়ে ডেটা বাইন্ডিং সাপোর্ট করে, অর্থাৎ আপনি সরাসরি আপনার টেমপ্লেটের টুকরোগুলো কম্পোনেন্টের সাথে এবং بالعکس কানেক্ট করতে পারেন।
উপরের ফর্মটি FormGroup ডেটা বাইন্ডিং পাওয়ার একটি ভালো উদাহরণ। এটি অটোমেটিক্যালি প্রতিটি ফর্ম ফিল্ডকে কম্পোনেন্টের মধ্যে তৈরি userForm অবজেক্টের সাথে বাইন্ড করে।
editUser মেথডে, উদাহরণস্বরূপ, আপনি বাইন্ডিং-এর বিপরীত ভার্সন দেখতে পাবেন, যেখানে userForm-এর মানগুলো কম্পোনেন্টের মধ্যে সেট করা হয় এবং ভিউতে ফর্মে প্রতিফলিত হবে।
ইন্ডেক্স ভিউ বিল্ড করা
আসুন index.component.html-এর কন্টেন্ট দুটি পার্টে ব্রেক ডাউন করি। এটি প্রথম পার্ট:
<div class="container pricing-header px-3 py-3 pt-md-5 pb-md-4 mx-auto text-center">
<h1 class="display-4">User's Listing</h1>
<p class="lead">A quick CRUD example of how to integrate Rails with Angular</p>
<table class="table">
<tr>
<th>Id</th>
<th>Name</th>
<th>Age</th>
<th>Address</th>
<th>Actions</th>
</tr>
<tbody>
<tr *ngFor="let user of users">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.age }}</td>
<td>{{ user.address }}</td>
<td colspan="2">
<button class="btn btn-secondary" (click)="editUser(user, template)">Edit</button> |
<button class="btn btn-danger" (click)="deleteUser(user.id)">Delete</button>
</td>
</tr>
</tbody>
</table>
<button class="btn btn-primary float-right mt-4" (click)="newUser(template)">Insert New</button>
</div>
এতে অধিকাংশ প্লেইন HTML। আমরা Bootstrap ক্লাসগুলোতে ডিটেইলসে যাব না।
এখানে গুরুত্বপূর্ণ পার্ট হলো টেবিলের রোতে ngFor ডিরেক্টিভ। এটি users অ্যারে (ইহা মনে আছে?) এর ওপর ইটারেট করতে সাহায্য করে এর প্রতিটি অ্যাট্রিবিউট HTML আউটপুটে প্রিন্ট করে {{ … }} অপারেটর দিয়ে।
যখনই আপনি DOM ইভেন্টগুলো যোগ করতে চান, যেমন onClick, শুধু ইভেন্টের নামকে প্যারেনথেসিস দিয়ে র্যাপ করুন এবং কম্পোনেন্ট ফাংশনটি যোগ করুন যা ক্লিক হলে কল হবে।
মডাল ভিউ বিল্ড করা
দ্বিতীয় পার্ট মডাল কন্টেন্ট সম্পর্কিত, তাই এটি উপরের নিচে যোগ করুন:
<ng-template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">{{ isNew ? "New User" : "Update User" }}</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form [formGroup]="userForm" (ngSubmit)="isNew ? createUser() : updateUser()" novalidate>
<input type="hidden" formControlName="id" class="form-control" />
<div class="form-group">
<label>Name</label>
<input type="text" formControlName="name" class="form-control" />
</div>
<div class="form-group">
<label>Age</label>
<input type="text" formControlName="age" class="form-control" />
</div>
<div class="form-group">
<label>Address</label>
<textarea class="form-control" formControlName="address" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</ng-template>
নোট করুন আমরা <ng-template> ট্যাগ ব্যবহার করছি, যা আপনাকে HTML এবং Angular-এর মধ্যে এলিমেন্ট্যাঙ্কর করতে দেয়। টেমপ্লেট আইডি # চিহ্নের ঠিক পরে আসে।
ফর্মের ভিতরেও, নোট করুন আমরা কম্পোনেন্ট ভেরিয়েবল isNew ব্যবহার করছি যাচাই করতে যে এই ফর্মের বর্তমান ব্যবহার ইউজার তৈরির জন্য কিনা আপডেটের জন্য।
শেষে, আমাদের পুরো hello_angular অ্যাপ্লিকেশনকে রেইলস index.html.erb পেজে ইনজেক্ট করতে হবে। তাই, views/users/ ফোল্ডারের অধীনে এই ফাইলটি খুলুন এবং এর কন্টেন্ট নিচের মতো পরিবর্তন করুন:
<hello-angular>We're almost done...</hello-angular>
<%= javascript_pack_tag 'hello_angular' %>
Angular মডিউলস
এখন, আমাদের Angular-কে বলতে হবে কোথা থেকে জিনিসগুলো খুঁজে বের করবে। এটি হয় এর মডিউল কনফিগারেশনে।
চলুন app-bootstrap.module.ts-এ কন্টেন্ট যোগ করি:
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { ModalModule } from "ngx-bootstrap/modal";
@NgModule({
imports: [CommonModule, ModalModule.forRoot()],
exports: [ModalModule],
})
export class AppBootstrapModule {}
এটি শুধু আমরা ngx-bootstrap থেকে ইনহেরিট করা Bootstrap কম্পোনেন্টগুলোর জন্য সীমাবদ্ধ। একমাত্র কম্পোনেন্ট যা আমরা अभी ব্যবহার করছি তা হলো Bootstrap মডাল।
তারপর, app-routing.module.ts ফাইলটি খুলুন এবং এর কন্টেন্ট নিচের মতো পরিবর্তন করুন:
import { RouterModule, Routes } from "@angular/router";
import { NgModule } from "@angular/core";
import { UserIndexComponent } from "./user/index/index.component";
const appRoutes: Routes = [
{ path: "users", component: UserIndexComponent },
{ path: "", redirectTo: "/users", pathMatch: "full" },
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes, { scrollPositionRestoration: "enabled" })],
exports: [RouterModule],
})
export class AppRoutingModule {}
এটি নিশ্চিত করবে যে Angular সঠিক User কম্পোনেন্ট ম্যাচ করে যখন /users পাথ কল করা হয়।
এবং, শেষে, उन সবকে মেইন AppModule ক্লাসে রেজিস্টার করুন। app.module.ts ফাইলটি খুলুন এবং নিশ্চিত করুন এটি নিচের মতো দেখায়:
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { HttpClientModule } from "@angular/common/http";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { AppComponent } from "./app.component";
import { AppRoutingModule } from "./app-routing.module";
import { AppBootstrapModule } from "./app-boostrap.module";
import { UserIndexComponent } from "./user/index/index.component";
@NgModule({
declarations: [AppComponent, UserIndexComponent],
imports: [HttpClientModule, AppRoutingModule, BrowserModule, FormsModule, ReactiveFormsModule, AppBootstrapModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
এখানে সবকিছু ম্যাপ করা। আমাদের ফর্ম থেকে, HTTP ক্লায়েন্ট এবং ইউজার কম্পোনেন্ট থেকে Bootstrap মডিউল কনফিগারেশন, এবং রাউটিং।
কনফিগারেশন ফিনিশিং আপ
টেস্টে যাওয়ার আগে, আমাদের কিছু জিনিস ফিনিশ করতে হবে, শুরু করে app.component.ts ফাইল:
import { Component } from "@angular/core";
@Component({
selector: "hello-angular",
template: "<router-outlet></router-outlet>",
})
export class AppComponent {
name = "Angular!";
}
মেইন অ্যাপ কম্পোনেন্টকে জানতে হবে কীভাবে পাথগুলো রাউট করবে, তাই RouterOutlet কাজটি করবে।
তারপর, আমাদের নিশ্চিত করতে হবে Webpacker আমরা যে HTML এক্সটেনশন নিয়ে কাজ করছি সেটা বুঝতে পারে। এর জন্য, webpacker.yml ফাইলটি খুলুন এবং, /config ফোল্ডারের অধীনে, extensions সেকশন খুঁজুন এবং নিচের আইটেমটি যোগ করুন:
- .html
Webpacker শুধু বিল্ট-ইন TypeScript লোডারকে রিকগনাইজ করে যা Angular-এর সাথে ডিফল্টলি আসে। আমাদের HTML প্রসেস করতে হবে, এটাই কারণ আমরা আগে html-loader ডিপেন্ডেন্সি ইনস্টল করেছিলাম। এটি সেট আপ করতে, environment.js ফাইলটি খুলুন, config/webpack ফোল্ডারের অধীনে, এবং নিচের লোডার কনফিগ যোগ করুন:
environment.loaders.append("html", {
test: /\.html$/,
use: [
{
loader: "html-loader",
options: {
minimize: true,
},
},
],
});
শেষে, আমাদের Angular সার্ভিস তাদের HTTP কলগুলোর ওপর এরর না পাওয়ার জন্য, আমাদের রেইলস যে CSRF টোকেন চেক করে সেটা ডিজেবল করতে হবে। এর জন্য, application_controller.rb ফাইলটি খুলুন, app/controllers ফোল্ডারের অধীনে, এবং এর কন্টেন্ট নিচের মতো পরিবর্তন করুন:
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
end
টেস্টিং
এটাই সব! সেটআপ অনেক কাস্টমাইজেশন চাইতে পারে বলে কিছুটা ট্রিকি দেখতে পারে, কিন্তু ফলাফলটা এর যোগ্য।
টেস্ট করতে, সবকিছু সেভ করুন, এবং সার্ভার শুরু করুন rails s কমান্ড ইস্যু করে।
তারপর, আপনার ওয়েব ব্রাউজারে যান এবং টাইপ করুন https://localhost:3000/users। আগে বড়ুন এবং CRUD ওয়েব অ্যাপ্লিকেশনটিতে খেলুন।
উপসংহার
এই CRUD চালু করার জন্য একটি লং রোড ছিল। প্রথম ট্রায়ালের পর, আপনি দেখবেন জিনিসগুলো আপনার ভবিষ্যতের প্রজেক্টের জন্য সহজ হয়ে যাচ্ছে। আশা করি এই প্রজেক্ট তাদের জন্য একটি স্ট্রেটিং পয়েন্ট সেট আপ করতে সাহায্য করবে যারা উভয় টেকনোলজি জড়িয়ে দ্রুত একটি প্রজেক্ট শুরু করতে চান।
যদিও আমাদের কাছে একটি ওপেন-সোর্স স্ক্যাফোল্ডিং প্রজেক্ট নেই সাহায্য করার জন্য, আমরা একে অপরের প্রচেষ্টার উপর নির্ভর করি যাতে এমন মেটেরিয়াল থাকে। এখন, আপনার পালা; প্রজেক্টটি ফর্ক করুন (অথবা স্ক্র্যাচ থেকে তৈরি করুন) এবং আপনার কাস্টমাইজেশন শুরু করুন।
এই উদাহরণের জন্য GitHub রিপোজিটরি এখানে পাওয়া যাবে। মজা করুন!