В этой статье я собираюсь объяснить, как выполнять грубую операцию в 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.

  1. Установка среды разработки - Установите Node.js и npm, если они не установлены.
  2. Установите 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));
}

В приведенном выше коде -

  1. Во второй строке - как вы видите - мы импортируем «файл-загрузчик» как рабочий путь. Это кажется запутанным, правда?

На самом деле я делаю здесь что-то вроде взлома - 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);
          });
      }
  
  }

В приведенном выше коде -

  1. Создается метод 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>

В приведенном выше коде -

  1. У меня есть цикл по переменной «студенты».
  2. Я также сохранил идентификатор студента как атрибут 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();
 }
}

В приведенном выше коде -

  1. Создан член класса newStudent. Это будет использоваться для хранения информации о новом ученике. В основном он будет использоваться для привязки к представлению.
  2. Написан метод addStudent. Он вызовет addStudent в службе, предоставляющей нового студента, который добавит данные в JsStore.
  3. Написан метод 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>

В приведенном выше коде -

  1. Мы добавили новую строку таблицы, которая используется для добавления студента. Мы связали newStudent с текстовым полем.
  2. Для добавления кнопки будет вызываться метод addStudent.
  3. метод 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
        }
      });
    }

В приведенном выше коде -

  1. Написан метод updateStudent, который обновит студента по идентификатору студента.
  2. Написан метод 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);
        });
    }
  
  }

В приведенном выше коде -

  1. Создан член класса oldStudent. Он используется для сохранения информации о студенте, находящейся в режиме редактирования.
  2. Создан метод getStudent, который будет использоваться для установки переменной oldStudent по идентификатору студента.
  3. Создается метод 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>

В приведенном выше коде -

  1. Мы сохранили временное редактирование переменных. Он будет использоваться для проверки того, находится ли ячейка таблицы в режиме редактирования или нет.
  2. При нажатии кнопки редактирования мы устанавливаем для редактирования значение true и вызываем getStudent, который устанавливает информацию о студенте внутри oldStudent.
  3. Когда нажимается кнопка «Обновить» - мы устанавливаем для редактирования значение false и вызываем updateStudent, который обновит студента.

Остальное - это простой html-код.

Теперь давайте проверим результат в браузере -

Наконец, мы закончили с Crud Operation.

Это было адское программирование. Спасибо, что прочитали это, ребята.

Вы можете скачать реализацию статьи здесь - Угловой пример

Ссылка