В этой статье я собираюсь объяснить, как выполнять грубую операцию в angular4, используя библиотеку-оболочку IndexedDB JsStore.
Если задумались - что такое JsStore?
JsStore - это оболочка IndexedDB. Он предоставляет простой sql, такой как api, для выполнения операций с базами данных и делает IndexedDB очень простым.
Прежде чем двигаться дальше - если вы не имеете ни малейшего представления о jsstore, я настоятельно рекомендую вам взглянуть на руководство по началу работы с jsstore - http://jsstore.net/tutorial/get-started/. Если вы хотите понять более подробно, создайте простую демонстрацию самостоятельно, как указано на странице Начало работы.
Итак, в этой статье мы заменим IndexedDB на JsStore.
Хватит слов, займемся чем-нибудь.
Если вам нужен исходный код, вы можете скачать его отсюда - https://github.com/ujjwalguptaofficial/JsStore/tree/master/examples/angular
Предпосылки
Вы должны иметь базовые знания
- html
- css
- javascript
- angular2 или более поздняя версия
- indexedb (не обязательно)
Давайте код
Создать Angular проект
Сначала нам нужно будет создать угловой проект. Я показываю вам, как работать с angular cli.
- Установка среды разработки - Установите Node.js и npm, если они не установлены.
- Установите angular cli - выполните приведенный ниже код в окне терминала.
npm install -g @angular/cli
3. Создайте новый проект - выполните команду ниже, чтобы создать проект angular.
ng new <AppName>
Вы можете выбрать любое имя приложения - я выбираю «my-app».
Пожалуйста, наберитесь терпения, создание проекта займет некоторое время.
4. Запустить проект - перейдите в каталог проекта и запустите проект.
Cd my-app ng serve
На компиляцию проекта уйдет некоторое время. Когда он будет скомпилирован, вы увидите сообщение - «Webpack успешно скомпилирован».
Теперь откройте в браузере адрес - http: // localhost: 4200 /. Вы увидите такой вывод -
Создать компонент и сервис
Выполните следующую команду, чтобы создать компонент -
ng generate component student
Этот компонент будет использоваться для написания бизнес-логики.
Теперь давайте создадим сервис для записи логики данных. Таким образом, наш код будет чистым и простым в обслуживании.
Запустите приведенный ниже код в терминале -
ng g service service/student
Это создаст новую студенческую службу внутри папки Service.
Теперь нам нужно добавить Service student внутри компонента student. Скопируйте приведенный ниже код внутрь файла - student.component.ts
import {
Component,
OnInit
} from '@angular/core';
import {
StudentService
} from '../service/student.service';
@Component({
selector: 'app-student',
templateUrl: './student.component.html',
styleUrls: ['./student.component.css'],
providers: [StudentService]
})
export class StudentComponent implements OnInit {
private _service: StudentService;
constructor(service: StudentService) {
this._service = service;
}
ngOnInit() {}
}
}
В приведенном выше коде я добавил StudentService в массив поставщиков, который будет внедрен как зависимость в конструктор StudentComponent с помощью angular.
Теперь проверим новый компонент. Нам нужно добавить тег селектора компонентов в app.component.html.
Замените код приведенным ниже кодом -
<app-student>
</app-student>
Скачать JsStore
Выполните следующую команду в терминале, чтобы установить JsStore -
npm install jsstore --save
он загрузит JsStore и сохранит зависимости в package.json.
Поскольку соединение с базой данных будет использоваться всеми сервисами, будет хорошо, если мы сохраним объект соединения в общем сервисе.
Итак, давайте создадим общий сервис. Выполните приведенный ниже код в терминале -
ng g service service/idb
Это создаст IdbService в служебной папке.
теперь нам нужно написать код, чтобы получить соединение. Скопируйте приведенный ниже код в idb.service.ts -
import * as JsStore from 'jsstore'; import * as workerPath from 'file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js'; export class IdbService { // this will make sure that we are using one connection // otherwise multiple instance will be created and thus multiple // worker and that may create some problems static idbCon = new JsStore.Instance(new Worker(workerPath)); }
В приведенном выше коде -
- Во второй строке - как вы видите - мы импортируем «файл-загрузчик» как рабочий путь. Это кажется запутанным, правда?
На самом деле я делаю здесь что-то вроде взлома - Angular использует веб-пакет и загрузчик файлов (плагин веб-пакета), который также используется angular для управления файлами. Я использую здесь файловый загрузчик, чтобы получить путь к jsstore.worker.min.js, который вы можете увидеть в запросе файлового загрузчика. Теперь этот путь будет передан в jsstore для создания рабочего.
Но поскольку мы находимся в проекте машинописного текста, нам нужно определить загрузчик файлов и сообщить компилятору машинописного текста, что это действительный код. Для этого создайте дополнительную папку и внутри нее файл «worker.d.ts». Вставьте содержимое ниже в файл.
declare module "file-loader?name=scripts/[name].[hash].js!*" { const value: string; export = value; }
2. мы объявляем idbCon статическим, что гарантирует, что мы поддерживаем только один экземпляр jsstore. Каждая служба будет использовать это соединение для выполнения запроса indexeddb.
Теперь нам нужно использовать это соединение в студенческой службе, но представьте, что если у нас есть несколько служб, все они должны использовать соединение, и, возможно, есть некоторые общие коды, которые должны использовать все службы, такие как ajaxhelper, некоторая общая служебная переменная и т. Д. Вот почему - нам нужно создать базовый сервис, который поможет нам убрать избыточность кода и сделать сервис более чистым и удобным в обслуживании.
Итак, давайте создадим базовую службу - выполните команду ниже в терминале
ng g service service/base
Это создаст базовую службу. Скопируйте приведенный ниже код в базовую службу -
import { Injectable } from '@angular/core'; import { IdbService } from './idb.service'; export class BaseService { constructor() { // turn on jsstore log status - help you to debug // turn it off in production or when you dont need this.connection.setLogStatus(true); } get connection() { return IdbService.idbCon; } }
Теперь нам нужно унаследовать базовую службу в службе студентов. Так что скопируйте приведенный ниже код
import { Injectable } from '@angular/core'; import { BaseService } from './base.service'; @Injectable({ providedIn: 'root' }) export class StudentService extends BaseService { constructor() { super(); } }
Выполните приведенную ниже команду, чтобы проверить, все ли в порядке.
ng build
Если он показывает ошибку - «В объявлениях внешнего перечисления инициализатор члена должен быть непрерывным выражением», то нам нужно обновить версию машинописного текста.
Чтобы обновить версию машинописного текста, выполните следующую команду -
npm install typescript@latest
теперь все настроено, нам просто нужно написать код.
Создать базу данных
Создать базу данных в JsStore просто. Он использует подход Sql - база данных состоит из нескольких таблиц, а таблица состоит из нескольких столбцов.
Пожалуйста, посмотрите документ jsstore, чтобы создать базу данных -
1. Создайте документ таблицы - http://jsstore.net/tutorial/table/
2. Создать документ базы данных - http://jsstore.net/tutorial/database/
Теперь давайте напишем код для создания базы данных и получения соединения. Скопируйте приведенный ниже код в base.service.ts -
import { IdbService } from './idb.service'; import { IDataBase, DATA_TYPE, ITable } from 'jsstore'; export class BaseService { dbname = 'Angular_Demo'; constructor() { // turn on jsstore log status - help you to debug // turn off it in production or when you dont need this.connection.setLogStatus(true); this.initJsStore(); } get connection() { return IdbService.idbCon; } initJsStore() { this.connection.isDbExist(this.dbname).then(isExist => { if (isExist) { this.connection.openDb(this.dbname); } else { const dataBase = this.getDatabase(); this.connection.createDb(dataBase); } }).catch(err => { // this will be fired when indexedDB is not supported. alert(err.message); }); } private getDatabase() { const tblStudent: ITable = { name: 'Students', columns: [{ name: 'id', primaryKey: true, autoIncrement: true }, { name: 'name', notNull: true, dataType: DATA_TYPE.String }, { name: 'gender', dataType: DATA_TYPE.String, default: 'male' }, { name: 'country', notNull: true, dataType: DATA_TYPE.String }, { name: 'city', dataType: DATA_TYPE.String, notNull: true } ] }; const dataBase: IDataBase = { name: this.dbname, tables: [tblStudent] }; return dataBase; } }
Приведенный выше код создаст базу данных, если она не существует, в противном случае откройте соединение с базой данных для указанного имени базы данных.
Прочитать данные
JsStore предоставляет API выбора для выбора данных из IndexedDB.
Пожалуйста, взгляните на выбранный документ api - http://jsstore.net/tutorial/select
Давайте сначала создадим модель студента - выполните следующую команду
ng generate class model/student
Это создаст класс Student в папке Model.
Теперь нам нужно определить нашу модель ученика. Поэтому скопируйте приведенный ниже код в файл student.ts в папке model -
export class IStudent {
id?: number;
name: string;
gender: string;
country: string;
city: string;
}
export class Student implements IStudent {
id = 0;
name = '';
gender = 'm';
country = '';
city = '';
}
В приведенном выше коде я также создал интерфейс. Хорошая практика - иметь интерфейс класса, и вы увидите, как мы собираемся его использовать.
Теперь давайте напишем код для выбора студентов из indexedDB. Поскольку это код, связанный с данными, мы напишем его в Service.
Скопируйте приведенный ниже код внутри класса StudentService -
getStudents() {
return this.connection.select({
from: 'Students'
});
}
Выглядит просто и чисто, правда?
Теперь нам нужно вызвать getStudents из компонента student. Скопируйте приведенный ниже код внутрь файла - student.component.ts
import {
Component,
OnInit
} from '@angular/core';
import {
StudentService
} from '../service/student.service';
import {
Student,
IStudent
} from '../model/student';
@Component({
selector: 'app-student',
templateUrl: './student.component.html',
styleUrls: ['./student.component.css'],
providers: [StudentService]
})
export class StudentComponent implements OnInit {
private service: StudentService;
students: Array = [];
constructor(service: StudentService) {
this.service = service;
}
ngOnInit() {
this.getStudents();
}
getStudents() {
this.service.getStudents().
then(students => {
this.students = students;
}).catch(error => {
console.error(error);
alert(error.message);
});
}
}
В приведенном выше коде -
- Создается метод getStudents, который вызывает метод - getStudents в сервисе и сохраняет список студентов внутри члена класса - student.
Мы написали бизнес-логику и логику данных для студентов. Теперь нам нужно написать код для просмотра. Так что давай напишем это.
Скопируйте приведенный ниже код внутрь файла - student.component.html
<table>
<tr>
<th>Student Name</th>
<th>Gender</th>
<th>Country</th>
<th>City</th>
</tr>
<tr *ngFor="let student of students" [attr.data-id]="student.id">
<td>{{student.name}}
</td>
<td>{{student.gender=='m'?'Male':'Female'}}
</td>
<td>{{student.country}}
</td>
<td>{{student.city}}</td>
</tr>
</table>
В приведенном выше коде -
- У меня есть цикл по переменной «студенты».
- Я также сохранил идентификатор студента как атрибут data_id. Мы будем использовать это позже для идентификации студента.
Перед запуском кода добавим несколько стилей. Скопируйте приведенный ниже код css в файл student.component.css -
table {
border-collapse: collapse;
}
table tr td,
th {
border: 1px solid black;
text-align: center;
padding: 10px;
}
contenteditable {
border: 2px solid blue;
}
Некоторые стили будут использованы позже. Надеюсь, вы понимаете эти CSS.
Теперь все готово. Итак, давайте посмотрим на результат в браузере. Выполните команду - ng serve и откройте адрес localhost: 4200.
Есть только заголовок таблицы, но нет данных. Это потому, что мы не вставили никаких данных.
Вставить данные
JsStore предоставляет API вставки для вставки данных в IndexedDB.
Пожалуйста, посмотрите вставку api doc - http://jsstore.net/tutorial/insert
Теперь нам нужно написать код для добавления студента. Итак, давайте напишем код в студенческой службе.
Скопируйте метод ниже в student.service.ts
addStudent(student: IStudent) {
return this.connection.insert({
into: 'Students',
return: true, // as id is autoincrement, so we would like to get the inserted value
values: [student]
});
}
теперь нам нужно вызвать addStudent из компонента. Скопируйте приведенный ниже код в student.component.ts -
import { Component, OnInit } from '@angular/core'; import { StudentService } from '../service/student.service'; import { Student, IStudent } from '../model/student'; @Component({ selector: 'app-student', templateUrl: './student.component.html', styleUrls: ['./student.component.css'], providers: [StudentService] }) export class StudentComponent implements OnInit { private service: StudentService; students: Array = []; newStudent: IStudent = new Student(); constructor(service: StudentService) { this.service = service; } ngOnInit() { this.getStudents(); } getStudents() { this.service.getStudents(). then(students => { this.students = students; }).catch(error => { console.error(error); alert(error.message); }); } addStudent() { this.service.addStudent(this.newStudent). then((addedStudents: IStudent[]) => { if (addedStudents.length > 0) { this.students.push(addedStudents[0]); this.clearNewStudent(); alert('Successfully added'); } }).catch(error => { console.error(error); alert(error.message); }); } clearNewStudent() { this.newStudent = new Student(); } }
В приведенном выше коде -
- Создан член класса newStudent. Это будет использоваться для хранения информации о новом ученике. В основном он будет использоваться для привязки к представлению.
- Написан метод addStudent. Он вызовет addStudent в службе, предоставляющей нового студента, который добавит данные в JsStore.
- Написан метод clearNewStudent, который очистит значение студента, записанное в текстовом поле.
теперь мы успешно написали бизнес-логику и логику данных. Пришло время создать представление для добавления данных.
Скопируйте приведенный ниже код внутрь файла - student.component.html
<table>
<tr>
<th>Student Name</th>
<th>Gender</th>
<th>Country</th>
<th>City</th>
<th></th>
<th></th>
</tr>
<tr>
<td><input type="text" [(ngModel)]="newStudent.name" /></td>
<td>
<select [(ngModel)]="newStudent.gender">
<option value="m">Male</option>
<option value="f">FeMale</option>
</select>
<td><input type="text" [(ngModel)]="newStudent.country" /></td>
<td><input type="text" [(ngModel)]="newStudent.city" /></td>
<td>
<button (click)="addStudent()">Add</button>
</td>
<td>
<button (click)="clearNewStudent()">Cancel</button>
</td>
</tr>
<tr *ngFor="let student of students" [attr.data-id]="student.id">
<td>{{student.name}}
</td>
<td>{{student.gender=='m'?'Male':'Female'}}
</td>
<td>{{student.country}}
</td>
<td>{{student.city}}</td>
<td></td>
<td></td>
</tr>
</table>
В приведенном выше коде -
- Мы добавили новую строку таблицы, которая используется для добавления студента. Мы связали newStudent с текстовым полем.
- Для добавления кнопки будет вызываться метод addStudent.
- метод clearNewStudent будет вызываться для кнопки отмены.
Теперь посмотрим на результат.
давайте протестируем функцию добавления -
Удалить данные
JsStore предоставляет api удаления для удаления данных.
Пожалуйста, прочтите документ об удалении api - http://jsstore.net/tutorial/remove/
Напишем код для удаления студента. Нам нужно удалить определенного студента, поэтому мы будем использовать идентификатор студента для удаления определенных данных.
Добавьте метод ниже в student.service.ts -
deleteStudent(studentId: number) { return this.connection.remove({ from: 'Students', where: { id: studentId } }); }
Позволяет вызвать этот код из компонента Student. Добавьте следующую функцию внутри компонента -
deleteStudent(studentId) {
this.service.deleteStudent(studentId).
then(rowsDeleted => {
if (rowsDeleted > 0) {
const index = this.students.findIndex(student => student.id === studentId);
this.students.splice(index, 1);
alert('Successfully deleted');
}
}).catch(error => {
console.error(error);
alert(error.message);
});
}
Теперь нам нужно создать представление для удаления данных. Просто добавьте приведенный ниже код в последнюю ячейку второй строки -
<td><button (click)="deleteStudent(student.id)">Delete</button></td>
Теперь все готово. Давайте протестируем код.
Обновить данные
JsStore предоставляет api обновления для обновления данных.
Документация по обновлению JsStore - http://jsstore.net/tutorial/update
Давайте напишем код для обновления студентов в студенческой службе. Скопируйте приведенный ниже код в student.service.ts
updateStudent(studentId: number, updateValue: IStudent) {
return this.connection.update({
in: 'Students',
where: {
id: studentId
},
set: updateValue
});
}
getStudent(studentId: number) {
return this.connection.select({
from: 'Students',
where: {
id: studentId
}
});
}
В приведенном выше коде -
- Написан метод updateStudent, который обновит студента по идентификатору студента.
- Написан метод getStudent, который возвращает студента по id.
Теперь нам нужно вызвать эти методы из компонента
import { Component, OnInit } from '@angular/core';
import { StudentService } from '../service/student.service';
import { Student, IStudent } from '../model/student';
@Component({
selector: 'app-student',
templateUrl: './student.component.html',
styleUrls: ['./student.component.css'],
providers: [StudentService]
})
export class StudentComponent implements OnInit {
private service: StudentService;
students: Array = [];
newStudent: IStudent = new Student();
oldStudent: IStudent = new Student();
constructor(service: StudentService) {
this.service = service;
}
ngOnInit() {
this.getStudents();
}
getStudents() {
this.service.getStudents().
then(students => {
this.students = students;
}).catch(error => {
console.error(error);
alert(error.message);
});
}
addStudent() {
this.service.addStudent(this.newStudent).
then((addedStudents: IStudent[]) => {
if (addedStudents.length > 0) {
this.students.push(addedStudents[0]);
this.clearNewStudent();
alert('Successfully added');
}
}).catch(error => {
console.error(error);
alert(error.message);
});
}
clearNewStudent() {
this.newStudent = new Student();
}
deleteStudent(studentId) {
this.service.deleteStudent(studentId).
then(rowsDeleted => {
if (rowsDeleted > 0) {
const index = this.students.findIndex(student => student.id === studentId);
this.students.splice(index, 1);
alert('Successfully deleted');
}
}).catch(error => {
console.error(error);
alert(error.message);
});
}
clearOldStudent() {
this.oldStudent = new Student();
}
getStudent(studentId) {
this.service.getStudent(studentId).
then(students => {
if (students.length > 0) {
this.oldStudent = students[0];
}
}).catch(error => {
console.error(error);
alert(error.message);
});
}
updateStudent() {
const updatedValue: IStudent = {
name: this.oldStudent.name,
gender: this.oldStudent.gender,
country: this.oldStudent.country,
city: this.oldStudent.city
};
this.service.updateStudent(this.oldStudent.id, updatedValue).
then(rowsUpdated => {
if (rowsUpdated > 0) {
const index = this.students.findIndex(student => student.id === this.oldStudent.id);
this.students[index] = this.oldStudent;
this.clearOldStudent();
alert('Successfully updated');
}
}).catch(error => {
console.error(error);
alert(error.message);
});
}
}
В приведенном выше коде -
- Создан член класса oldStudent. Он используется для сохранения информации о студенте, находящейся в режиме редактирования.
- Создан метод getStudent, который будет использоваться для установки переменной oldStudent по идентификатору студента.
- Создается метод updateStudent, который будет использоваться для обновления редактируемого студента.
Круто, теперь мы остались с видом. Скопируйте приведенный ниже html-код -
<table>
<tr>
<th>Student Name</th>
<th>gender</th>
<th>country</th>
<th>city</th>
<th></th>
<th></th>
</tr>
<tr>
<td>
<input type="text" [(ngModel)]="newStudent.name" />
</td>
<td>
<select [(ngModel)]="newStudent.gender">
<option value="m">Male</option>
<option value="f">FeMale</option>
</select>
</td>
<td>
<input type="text" [(ngModel)]="newStudent.country" />
</td>
<td>
<input type="text" [(ngModel)]="newStudent.city" />
</td>
<td>
<button (click)="addStudent()">Add</button>
</td>
<td>
<button (click)="clearNewStudent()">Cancel</button>
</td>
</tr>
<tr *ngFor="let student of students" [attr.data-id]="student.id">
<td>
<input type="text" *ngIf="student.editing" [(ngModel)]="oldStudent.name" />
<span *ngIf="!student.editing">
{{student.name}}
</span>
</td>
<td>
<select *ngIf="student.editing" [(ngModel)]="oldStudent.gender">
<option value="m">Male</option>
<option value="f">FeMale</option>
</select>
<span *ngIf="!student.editing">{{student.gender=='m'?'Male':'Female'}}</span>
</td>
<td>
<input type="text" *ngIf="student.editing" [(ngModel)]="oldStudent.country" />
<span *ngIf="!student.editing">{{student.country}}</span>
</td>
<td>
<input type="text" *ngIf="student.editing" [(ngModel)]="oldStudent.city" />
<span *ngIf="!student.editing">{{student.city}}</span>
</td>
<td>
<button *ngIf="student.editing" (click)="updateStudent();student.editing=false">Update</button>
<button *ngIf="!student.editing" (click)="student.editing=true;getStudent(student.id);">Edit</button>
</td>
<td>
<button *ngIf="student.editing" (click)="student.editing=false">Cancel</button>
<button *ngIf="!student.editing" (click)="deleteStudent(student.id)">Delete</button>
</td>
</tr>
</table>
В приведенном выше коде -
- Мы сохранили временное редактирование переменных. Он будет использоваться для проверки того, находится ли ячейка таблицы в режиме редактирования или нет.
- При нажатии кнопки редактирования мы устанавливаем для редактирования значение true и вызываем getStudent, который устанавливает информацию о студенте внутри oldStudent.
- Когда нажимается кнопка «Обновить» - мы устанавливаем для редактирования значение false и вызываем updateStudent, который обновит студента.
Остальное - это простой html-код.
Теперь давайте проверим результат в браузере -
Наконец, мы закончили с Crud Operation.
Это было адское программирование. Спасибо, что прочитали это, ребята.
Вы можете скачать реализацию статьи здесь - Угловой пример