MEAN — это сокращение от MongoDB, Express, Angular и Node.js. MEAN — один из популярных технологических стеков, используемых для разработки веб-приложений. В нем используется Javascript во фронтенде и бэкенде. Все компоненты стека MEAN находятся в открытом доступе, и разработчик может свободно их модифицировать. Angular использует архитектуру MVC для организации приложения, обеспечивая тем самым быструю разработку вашего приложения.
Существуют вариации стека MEAN, такие как MERN (замена Angular.js на React.js) и MEVN (использование Vue.js).
В этой статье мы создадим базовое MEAN-приложение для хранения и получения информации о сотрудниках из базы данных (основные CRUD-операции).
- Начало работы
- Настройка среды
- Требования
- Часть1 — Настройка бэкенда Node.JS
- Установите необходимые пакеты
- Создание модели
- Настройка контроллера
- Настройка маршрутов
- Настройка сервера
- Часть2 — Настройка фронтенда Angular
- Создайте ангулярный проект
- Интеграция Bootstrap
- Генерация компонентов
- Активируйте службу маршрутизации
- Создание сервиса Angular
- Создайте файл модели сотрудника
- Создайте сервис
- Регистрация сотрудника
- Показать список сотрудников
- Редактирование сотрудника
Начало работы
Настройка среды
Требования
- Node.Js [скачать]
- MongoDB [скачать]
- Postman [скачать]
- Visual Studio Code или любой текстовый редактор [скачать]
Если у вас не установлены перечисленные программы, скачайте и установите их с официального сайта на вашей машине. Убедитесь, что вы добавили путь к mongodb и node.js в переменные окружения.
Проверьте версии node.js
и mongodb
с помощью следующей команды.
npm --version
mongo --version
Часть1 — Настройка бэкенда Node.JS
Мы можем организовать файлы бэкенда и фронтенда в отдельных папках. Для этого создайте папку backend и перейдите в нее с помощью следующей команды.
mkdir backend
cd backend
Инициализируйте проект backend nodejs с помощью следующей команды.
npm init
npm init
предложит вам ввести некоторую базовую информацию, такую как название приложения, описание, версия, автор и ключевое слово. Введите эту информацию и нажмите Enter для завершения процесса. После создания проекта в каталоге появится файл package.json, содержащий основную информацию о проекте, а также зависимости проекта.
Добавьте команду start в файл package.json. Для этого откройте VSCode и добавьте в него следующий скрипт.
"start": "node index.js"
- Создайте файл с именем
index.js
для написания кода сервера. - Создайте три папки —
models
,controllers
иroutes
. - Создайте файл с именем
employee.js
во всех трех папках.
Окончательная структура проекта выглядит следующим образом:
Установите необходимые пакеты
Выполните следующую команду в терминале в корневой папке, чтобы добавить в проект пакеты body-parser, cors, express и mongoose.
npm install body-parser cors express mongoose
Создание модели
Мы начнем с определения схемы для коллекции сотрудников. Коллекция сотрудников содержит имя, email, должность и phoneNumber.
Чтобы определить модель сотрудника, добавьте следующий код в файл backend > models > employee.js
.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Define collection and schema
let Employee = new Schema({
name: {
type: String
},
email: {
type: String
},
designation: {
type: String
},
phoneNumber: {
type: Number
}
}, {
collection: 'employees'
})
module.exports = mongoose.model('Employee', Employee)
Настройка контроллера
Контроллер содержит бизнес-логику для доступа к данным из базы данных с помощью различных маршрутов. Здесь мы будем использовать mongoose для выполнения CRUD-операций над базой данных MongoDB.
Чтобы создать контроллер, добавьте следующий код в файл backend > controllers > employee.js
.
var mongoose = require('mongoose'),
Employee = mongoose.model('Employee');
exports.listAllEmployee = function(req, res) {
Employee.find({}, function(err, Employee) {
if (err)
res.send(err);
res.json(Employee);
});
};
exports.createEmployee = function(req, res) {
var emp = new Employee(req.body);
emp.save(function(err, result) {
if (err)
res.send(err);
res.json(result);
});
};
exports.readEmployee = function(req, res) {
Employee.findById(req.params.employeeId, function(err, result) {
if (err)
res.send(err);
res.json(result);
});
};
exports.updateEmployee = function(req, res) {
Employee.findOneAndUpdate({_id: req.params.employeeId}, req.body, {new: true}, function(err, result) {
if (err)
res.send(err);
res.json(result);
});
};
exports.deleteEmployee = function(req, res) {
Employee.remove({
_id: req.params.employeeId
}, function(err, result) {
if (err)
res.send(err);
res.json({ message: 'Employee successfully deleted' });
});
};
Настройка маршрутов
Маршруты — это способы доступа к данным из базы данных с помощью контроллеров.
Чтобы создать маршруты, добавьте следующий код в файл backend > routes > employee.js
.
module.exports = function(app) {
var employee = require('./../controllers/employee');
app.route('/')
.get(employee.listAllEmployee)
app.route('/employee')
.get(employee.listAllEmployee)
.post(employee.createEmployee);
app.route('/employee/:employeeId')
.get(employee.readEmployee)
.put(employee.updateEmployee)
.delete(employee.deleteEmployee);
};
Настройка сервера
В коде мы указали модель, контроллеры и маршруты для хранения и получения данных о сотрудниках. Напишите файл сервера для объединения всей этой информации. Для этого откройте файл backend > index.js
и добавьте в него следующий код.
var express = require('express'),
app = express(),
port = process.env.PORT || 3000,
mongoose = require('mongoose'),
cors = require('cors'),
bodyParser = require('body-parser'),
Employee = require('./models/employee');
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost:27017/empdb', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log('Database sucessfully connected')
},
error => {
console.log('Database could not connected: ' + error)
}
)
// Setting up configurations
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
// Setting up the routes
var employeeRoute = require('./routes/employee');
//importing route
employeeRoute(app);
//register the route
app.listen(port, () => {
console.log('Connected to port ' + port)
})
// Find 404 and hand over to error handler
app.use((req, res, next) => {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
console.error(err.message);
if (!err.statusCode) err.statusCode = 500;
// If err has no specified error code, set error code to 'Internal Server Error (500)'
res.status(err.statusCode).send(err.message);
// All HTTP requests must have a response, so let's send back an error with its status code and message
});
Поймите код,
- Инициализировал переменные для express app, cors, body-parser, mongodb и модели.
- Создали соединение между сервером и базой данных mongodb с помощью метода mongoose.connect(), указав в качестве аргумента url mongodb.
- Настроили конфигурацию cors для сервера.
- Настройте маршруты для apis, импортировав и зарегистрировав маршрут в express app.
- Запустите сервер на порту 3000.
Выполните следующую команду для запуска сервера node.js.
npm start
Используйте postman для доступа к apis. В качестве альтернативы загрузите в браузер url http://localhost:3000/employee
. Если сервер работает, вы получите пустой массив []
.
Часть2 — Настройка фронтенда Angular
Angular — это платформа разработки с открытым исходным кодом для создания веб-приложений на основе сценариев. Она использует интерфейс командной строки под названием Angular CLI для разработки и поддержки приложений Angular непосредственно из терминала.
Установите angular-cli на вашей машине с помощью следующей команды, игнорируйте, если он уже установлен.
npm install -g @angular/cli
Создайте ангулярный проект
Создайте папку с именем frontend для хранения проекта angular.
Создайте приложение angular с помощью команды ng new.
mkdir frontend
cd frontend
ng new mean-stack-crud-app
Angular CLI запрашивает следующее при настройке проекта.
- Хотите ли вы добавить маршрутизацию Angular? Выберите y и нажмите enter.
- Какой формат таблицы стилей вы хотите использовать? Выберите CSS с помощью стрелок и нажмите enter.
Перейдите в папку проекта (mean-stack-crud-app) и откройте в ней код visual studio.
cd mean-stack-crud-app
code .
Интеграция Bootstrap
Bootstrap — это инструмент с открытым исходным кодом для создания отзывчивых веб-приложений. В этом проекте мы будем использовать шаблонизацию bootstrap.
Установите bootstrap в проект с помощью следующей команды,
npm install bootstrap
Добавьте следующий код в «styles» [ ] в массив angular.json.
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
]
Генерация компонентов
Компоненты — это строительные блоки приложения Angular. Каждый компонент состоит из HTML-шаблона, который отображает страницу, и класса typescript, который реализует поведение.
Сгенерируйте компоненты для добавления, обновления и просмотра данных о сотруднике с помощью следующих команд.
ng g c components/employee-create
ng g c components/employee-edit
ng g c components/employee-list
Активируйте службу маршрутизации
Маршрутизация — это важный инструмент для навигации между различными компонентами. Angular-cli создаст маршрутизацию по умолчанию для вашего приложения, если вы включите маршрутизацию при создании проекта. Для этого он создает app-routing.module.ts и регистрирует его в файле src > app > app.module.ts
.
Мы создали 3 компонента для управления данными о сотрудниках. Чтобы создать различные маршруты для доступа к ним, замените код app.module.ts
следующим кодом.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EmployeeCreateComponent } from './components/employee-create/employee-create.component';
import { EmployeeEditComponent } from './components/employee-edit/employee-edit.component';
import { EmployeeListComponent } from './components/employee-list/employee-list.component';import { HttpClientModule } from '@angular/common/http';
import { ApiService } from './service/api.service';const routes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'create-employee' },
{ path: 'create-employee', component: EmployeeCreateComponent },
{ path: 'edit-employee/:id', component: EmployeeEditComponent },
{ path: 'employees-list', component: EmployeeListComponent }
];
@NgModule({
declarations: [
AppComponent,
EmployeeCreateComponent,
EmployeeEditComponent,
EmployeeListComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
RouterModule.forRoot(routes),
HttpClientModule,
],
exports: [RouterModule],
providers: [ApiService],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.html
содержит несколько фиктивных кодов. Чтобы получить доступ к ссылкам маршрутизатора в компоненте, добавьте тег router-outlet в HTML-файл.
Замените содержимое файла app.component.html
следующим кодом.
<nav>
<a routerLinkActive="active" routerLink="/employees-list">View Employees</a>
<a routerLinkActive="active" routerLink="/create-employee">Add Employee</a>
</nav><router-outlet></router-outlet>
Создание сервиса Angular
В angular сервисы — это классы typescript с декоратором @Injectable. Они используются для организации и обмена данными с различными компонентами приложения Angular.
Настройка модуля HttpClientModule
Нам необходимо импортировать сервис HttpClientModule
в файл app.module.ts
, чтобы управлять данными с помощью объекта httpClient в файле сервиса.
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule
]
})
Создайте файл модели сотрудника
Создайте файл src > model > employee.ts
с помощью следующей команды,
ng g cl model/employee
Добавьте в него следующий код.
export class Employee {
name: string;
email: string;
designation: string;
phoneNumber: number;
constructor(name: string, email: string, designation: string, phoneNumber: number){
this.name = name;
this.email = email;
this.designation = designation;
this.phoneNumber = phoneNumber;
}
}
Создайте сервис
Создайте службу angular с помощью следующей команды,
ng g s service/api
Добавьте в него следующий код.
import { Injectable } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ApiService {
baseUri:string = 'http://localhost:3000';
headers = new HttpHeaders().set('Content-Type', 'application/json');constructor(private http: HttpClient) { }
// Create
createEmployee(data: any): Observable<any> {
let url = `${this.baseUri}/employee`;
return this.http.post(url, data)
.pipe(
catchError(this.errorMgmt)
)
}
// Get all employees
getEmployees() {
return this.http.get(`${this.baseUri}`);
}
// Get employee by id
getEmployee(id: any): Observable<any> {
let url = `${this.baseUri}/employee/${id}`;
return this.http.get(url, {headers: this.headers}).pipe(
map((res: any) => {
return res || {}
}),
catchError(this.errorMgmt)
)
}
// Update employee
updateEmployee(id: any, data: any): Observable<any> {
let url = `${this.baseUri}/employee/${id}`;
return this.http.put(url, data, { headers: this.headers }).pipe(
catchError(this.errorMgmt)
)
}
// Delete employee
deleteEmployee(id: any): Observable<any> {
let url = `${this.baseUri}/employee/${id}`;
return this.http.delete(url, { headers: this.headers }).pipe(
catchError(this.errorMgmt)
)
}
// Error handling
errorMgmt(error: HttpErrorResponse) {
let errorMessage = '';
if (error.error instanceof ErrorEvent) {
// Get client-side error
errorMessage = error.error.message;
} else {
// Get server-side error
errorMessage = `Error Code: ${error.status}nMessage: ${error.message}`;
}
console.log(errorMessage);
return throwError(errorMessage);
}}
Добавьте сервис в массив providers
файла app.module.ts
.
import { ApiService } from './service/api.service';
@NgModule({
providers: [ApiService]
})
Регистрация сотрудника
Мы настроили приложение angular и создали для него сервисы. Теперь мы можем сосредоточиться на бизнес-логике для регистрации компонента employee и компонента employee view. В этом руководстве мы будем использовать Reactive Forms для регистрации сотрудника.
Angular ReactiveForms
Откройте файл components > employee-create > employee-create.component.ts
в VSCode и добавьте в него следующий код.
import { Router } from '@angular/router';
import { ApiService } from './../../service/api.service';
import { Component, OnInit, NgZone } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
@Component({
selector: 'app-employee-create',
templateUrl: './employee-create.component.html',
styleUrls: ['./employee-create.component.css']
})
export class EmployeeCreateComponent implements OnInit {
submitted = false;
employeeForm: FormGroup;
EmployeeProfile:any = ['Finance', 'BDM', 'HR', 'Sales', 'Admin']
constructor(
public fb: FormBuilder,
private router: Router,
private ngZone: NgZone,
private apiService: ApiService
) {
this.employeeForm = this.fb.group({
name: ['', [Validators.required]],
email: ['', [Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,3}$')]],
designation: ['', [Validators.required]],
phoneNumber: ['', [Validators.required, Validators.pattern('^[0-9]+$')]]
})
}
ngOnInit() { }
// Choose designation with select dropdown
updateProfile(e: any){
var element = e.target as HTMLSelectElement
this.employeeForm?.get('designation')?.setValue(element.value, {
onlySelf: true
})
}
// Getter to access form control
get myForm(){
return this.employeeForm.controls;
}
onSubmit() {
this.submitted = true;
if (!this.employeeForm.valid) {
return false;
} else { this.apiService.createEmployee(this.employeeForm.value).subscribe(
(res) => {
console.log('Employee successfully created!')
this.ngZone.run(() => this.router.navigateByUrl('/employees-list'))
}, (error) => {
console.log(error);
});
return true;
}
}}
Откройте файл employee-create.component.html
и добавьте в него следующий код.
<div class="row justify-content-center">
<div class="col-md-4 register-employee">
<!-- form card register -->
<div class="card-body">
<form [formGroup]="employeeForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="inputName">Name</label>
<input class="form-control" type="text" formControlName="name">
<!-- error -->
<div class="invalid-feedback" *ngIf="submitted && myForm.name.errors?.required">
Name is required.
</div>
</div>
<div class="form-group">
<label for="inputEmail3">Email</label>
<input class="form-control" type="text" formControlName="email">
<!-- error -->
<div class="invalid-feedback" *ngIf="submitted && myForm.email.errors?.required">
Enter your email.
</div>
<div class="invalid-feedback" *ngIf="submitted && myForm.email.errors?.pattern">
Enter a valid email.
</div>
</div>
<div class="form-group">
<label for="inputPassword3">Designation</label>
<select class="custom-select form-control" (change)="updateProfile($event)"
formControlName="designation">
<option value="">Choose...</option>
<option *ngFor="let employeeProfile of EmployeeProfile" value="{{employeeProfile}}">{{employeeProfile}}
</option>
</select>
<!-- error -->
<div class="invalid-feedback" *ngIf="submitted && myForm.designation.errors?.required">
Choose designation.
</div>
</div>
<div class="form-group">
<label for="inputVerify3">Mobile No</label>
<input class="form-control" type="text" formControlName="phoneNumber">
<!-- error -->
<div class="invalid-feedback" *ngIf="submitted && myForm.phoneNumber.errors?.required">
Enter your phone number.
</div>
<div class="invalid-feedback" *ngIf="submitted && myForm.phoneNumber.errors?.pattern">
Enter Numbers Only
</div>
</div>
<div class="form-group">
<button class="btn btn-success btn-lg btn-block" type="submit">Register</button>
</div>
</form>
</div>
</div>
<!-- form card register -->
</div>
Показать список сотрудников
Откройте файл src/app/components/employee-list/employee-list.component.ts
и добавьте в него следующий код.
import { Component, OnInit } from '@angular/core';
import { ApiService } from './../../service/api.service';
@Component({
selector: 'app-employee-list',
templateUrl: './employee-list.component.html',
styleUrls: ['./employee-list.component.css']
})
export class EmployeeListComponent implements OnInit {
Employee:any = [];constructor(private apiService: ApiService) {
this.readEmployee();
}
ngOnInit() {}
readEmployee(){
this.apiService.getEmployees().subscribe((data) => {
this.Employee = data;
})
}
removeEmployee(employee: any, index: number) {
if(window.confirm('Are you sure?')) {
this.apiService.deleteEmployee(employee._id).subscribe((data) => {
this.Employee.splice(index, 1);
}
)
}
}}
Откройте файл employee-list.component.html
и добавьте в него следующий код.
<div class="container">
<!-- No data message -->
<p *ngIf="Employee.length <= 0" class="no-data text-center">There is no employee added yet!</p>
<!-- Employee list -->
<table class="table table-bordered" *ngIf="Employee.length > 0">
<thead class="table-success">
<tr>
<th scope="col">Employee ID</th>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Designation</th>
<th scope="col">Phone No</th>
<th scope="col center">Update</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employee of Employee; let i = index">
<th scope="row">{{employee._id}}</th>
<td>{{employee.name}}</td>
<td>{{employee.email}}</td>
<td>{{employee.designation}}</td>
<td>{{employee.phoneNumber}}</td>
<td class="text-center edit-block">
<span class="edit" [routerLink]="['/edit-employee/', employee._id]">
<button type="button" class="btn btn-success btn-sm">Edit</button>
</span>
<span class="delete" (click)="removeEmployee(employee, i)">
<button type="button" class="btn btn-danger btn-sm">Delete</button>
</span>
</td>
</tr>
</tbody>
</table>
</div>
Редактирование сотрудника
Откройте файл src/app/components/employee-edit/employee-edit.component.ts
и добавьте в него следующий код.
import { Employee } from './../../model/employee';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from "@angular/router";
import { ApiService } from './../../service/api.service';
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
@Component({
selector: 'app-employee-edit',
templateUrl: './employee-edit.component.html',
styleUrls: ['./employee-edit.component.css']
})
export class EmployeeEditComponent implements OnInit {
submitted = false;
editForm: FormGroup;
employeeData: Employee[];
EmployeeProfile: any = ['Finance', 'BDM', 'HR', 'Sales', 'Admin']
constructor(
public fb: FormBuilder,
private actRoute: ActivatedRoute,
private apiService: ApiService,
private router: Router
) {
this.employeeData = []
this.editForm = this.fb.group({})
}
ngOnInit() {
this.updateEmployee();
let id = this.actRoute.snapshot.paramMap.get('id');
this.getEmployee(id);
this.editForm = this.fb.group({
name: ['', [Validators.required]],
email: ['', [Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,3}$')]],
designation: ['', [Validators.required]],
phoneNumber: ['', [Validators.required, Validators.pattern('^[0-9]+$')]]
})
}
// Choose options with select-dropdown
updateProfile(e: any) {
var element = e.target as HTMLSelectElement
this.editForm?.get('designation')?.setValue(element.value, {
onlySelf: true
})
}
// Getter to access form control
get myForm() {
return this.editForm.controls;
}
getEmployee(id: any) {
this.apiService.getEmployee(id).subscribe(data => {
this.editForm.setValue({
name: data['name'],
email: data['email'],
designation: data['designation'],
phoneNumber: data['phoneNumber'],
});
});
}
updateEmployee() {
this.editForm = this.fb.group({
name: ['', [Validators.required]],
email: ['', [Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,3}$')]],
designation: ['', [Validators.required]],
phoneNumber: ['', [Validators.required, Validators.pattern('^[0-9]+$')]]
})
}
onSubmit() {
this.submitted = true;
if (!this.editForm.valid) {
return false;
} else {
if (window.confirm('Are you sure?')) {
let id = this.actRoute.snapshot.paramMap.get('id');
this.apiService.updateEmployee(id, this.editForm.value)
.subscribe(res => {
this.router.navigateByUrl('/employees-list');
console.log('Content updated successfully!')
}, (error) => {
console.log(error)
})
}
return true;
}
}}
Откройте файл employee-edit.component.html
и добавьте в него следующий код.
<div class="row justify-content-center">
<div class="col-md-4 register-employee">
<!-- form card register -->
<div class="card card-outline-secondary">
<div class="card-header">
<h3 class="mb-0">Edit Employee</h3>
</div>
<div class="card-body">
<form [formGroup]="editForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="inputName">Name</label>
<input class="form-control" type="text" formControlName="name">
<div class="invalid-feedback" *ngIf="submitted && myForm.name.errors?.required">
Name is required.
</div>
</div>
<div class="form-group">
<label for="inputEmail3">Email</label>
<input class="form-control" type="text" formControlName="email">
<!-- error -->
<div class="invalid-feedback" *ngIf="submitted && myForm.email.errors?.required">
Enter your email.
</div>
<div class="invalid-feedback" *ngIf="submitted && myForm.email.errors?.pattern">
Enter valid email.
</div>
</div>
<div class="form-group">
<label for="inputPassword3">Designation</label>
<select class="custom-select form-control" (change)="updateProfile($event)"
formControlName="designation">
<option value="">Choose...</option>
<option *ngFor="let employeeProfile of EmployeeProfile" value="{{employeeProfile}}">{{employeeProfile}}
</option>
</select>
<!-- error -->
<div class="invalid-feedback" *ngIf="submitted && myForm.designation.errors?.required">
Choose designation.
</div>
</div>
<div class="form-group">
<label for="inputVerify3">Mobile No</label>
<input class="form-control" type="text" formControlName="phoneNumber">
<!-- error -->
<div class="invalid-feedback" *ngIf="submitted && myForm.phoneNumber.errors?.required">
Enter your phone number.
</div>
<div class="invalid-feedback" *ngIf="submitted && myForm.phoneNumber.errors?.pattern">
Enter Numbers Only
</div>
</div>
<div class="form-group">
<button class="btn btn-success btn-lg btn-block" type="submit">Update</button>
</div>
</form>
</div>
</div>
<!-- form -->
</div>
</div>
Вот и все! Ваше первое приложение на MEAN стеке 🙂
Спасибо, что прочитали эту статью.
Спасибо Gowri M Bhatt за обзор контента.
Если вам понравилась эта статья, пожалуйста, нажмите на кнопку с сердечком ♥ и поделитесь, чтобы помочь другим найти ее!
Статья также доступна на Medium.
Полный исходный код этого руководства можно найти здесь,
- GitHub — codemaker2015/mean-stack-crud-demo: Веб-приложение на основе Angular с nodejs и mongodb
- Angular
- Что такое MEAN Stack