Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
23_ИСТ_1_1_Какушкина_Ольга_ЛР_6.1.docx
Скачиваний:
0
Добавлен:
23.06.2025
Размер:
636.89 Кб
Скачать

М ИНОБРНАУКИ РОССИИ

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ

УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ

НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ

УНИВЕРСИТЕТ ИМ. Р.Е.АЛЕКСЕЕВА

Институт радиоэлектроники и информационных технологий

Кафедра «Графические информационные системы»

ОТЧЕТ

к лабораторной работе №6.1

«Инициализация и валидация форм. Работа с сервером.»

(наименование работы)

по дисциплине

«WEB-технологии»

(наименование дисциплины)

ПРОВЕРИЛ:

Агафонов Н.Е.

(подпись)

(фамилия, и.,о.)

СТУДЕНТ:

Какушкна О.В

(подпись)

(фамилия, и.,о.)

23-ИСТ-1-1

(шифр группы)

Оглавление

МИНОБРНАУКИ РОССИИ 1

НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ 1

1 Введение 3

1.1 Цели и задачи 3

1.1.1 Цель работы: 3

1.1.2 Постановка задачи: 3

2 Основная Часть 4

3 Заключение 19

  1. Введение

    1. Цели и задачи

      1. Цель работы:

Инициализация и валидация форм. Работа с сервером..

      1. Постановка задачи:

  • Инициализировать и валидировать формы

  • Произвести отправку значений формы на сервер

  • Произвести получения значений с сервера

  1. Основная Часть

Форма регистрации

Шаблон формы регистрации:

<form [formGroup]="registrationForm" (ngSubmit)="onRegister()" class="container_registration">

  <div *ngIf="showSuccessMessage" class="success-message">

    <p>Вы успешно зарегистрировались!</p>

  </div>

  <div class="textbox-container" *ngIf="registrationForm.get('firstName')">

    <label for="firstName">Имя:</label>

    <input id="firstName" formControlName="firstName" class="input_cnt" />

    <div *ngIf="registrationForm.get('firstName')?.invalid && (registrationForm.get('firstName')?.touched || registrationForm.get('firstName')?.dirty)" class="error-message">

      <div *ngIf="registrationForm.get('firstName')?.errors?.['required']">Это поле обязательно для заполнения.</div>

      <div *ngIf="registrationForm.get('firstName')?.errors?.['invalidName']">Имя должно содержать только буквы.</div>

    </div>

  </div>

  <div class="textbox-container">

    <label for="lastName">Фамилия:</label>

    <input id="lastName" formControlName="lastName" class="input_cnt" />

    <div *ngIf="registrationForm.get('lastName')?.invalid && (registrationForm.get('lastName')?.touched || registrationForm.get('lastName')?.dirty)" class="error-message">

      <div *ngIf="registrationForm.get('lastName')?.errors?.['required']">Это поле обязательно для заполнения.</div>

    </div>

  </div>

  <div class="textbox-container">

    <label for="email">Почта:</label>

    <input id="email" formControlName="email" class="input_cnt" />

    <div *ngIf="registrationForm.get('email')?.touched && registrationForm.get('email')?.invalid" class="error-message">

      <div *ngIf="registrationForm.get('email')?.errors?.['required']">Почта обязательна для заполнения.</div>

      <div *ngIf="registrationForm.get('email')?.errors?.['email']">Неверный формат почты.</div>

    </div>

    <div *ngIf="emailExists && registrationForm.get('email')?.touched" class="error-message">

      <p>Email уже существует. Пожалуйста, используйте другой.</p>

    </div>

  </div>

  <div class="textbox-container">

    <label for="password">Пароль:</label>

    <div class="input-container">  

      <input id="password" [type]="showPassword ? 'text' : 'password'" formControlName="password" class="input_cnt" />

      <span class="password-icon" (click)="showPassword = !showPassword">

        <i [ngClass]="showPassword ? 'fa fa-eye' : 'fa fa-eye-slash'"></i>

      </span>

    </div>

    <div *ngIf="registrationForm.get('password')?.invalid && (registrationForm.get('password')?.touched || registrationForm.get('password')?.dirty)" class="error-message">

      <div *ngIf="registrationForm.get('password')?.errors?.['required']">Поле обязательно для заполнения.</div>

      <div *ngIf="registrationForm.get('password')?.errors?.['minlength']">Пароль должен содержать минимум 8 символов.</div>

      <div *ngIf="registrationForm.get('password')?.errors?.['passwordWeak']">Пароль должен содержать заглавные буквы, строчные буквы, цифры и специальные символы.</div>

    </div>

  </div>

  <div class="textbox-container">

    <label for="section">Секция:</label>

    <select formControlName="section" class="form-control" class="input_cnt">

      <option *ngFor="let section of sections" [value]="section.id">

        {{ section.title }} (Доступно мест: {{ section.capacity  }})

      </option>

    </select>

    <div *ngIf="registrationForm.get('section')?.invalid && (registrationForm.get('section')?.touched || registrationForm.get('section')?.dirty)" class="error-message">

      Поле обязательно для заполнения.

    </div>

  </div>

  <div class="textbox-container">

    <label for="group">Группа:</label>

    <input id="group" formControlName="group" class="input_cnt" />

    <div *ngIf="registrationForm.get('group')?.invalid && (registrationForm.get('group')?.touched || registrationForm.get('group')?.dirty)" class="error-message">

      <div *ngIf="registrationForm.get('group')?.errors?.['required']">Поле обязательно для заполнения.</div>

      <div *ngIf="registrationForm.get('group')?.errors?.['invalidGroup']">Группа должна соответствовать формату XX-ЛЛЛ-X-X.</div>

    </div>

  </div>

  <div class="textbox-container">

    <label for="institute">Институт:</label>

    <select id="institute" formControlName="institute" class="input_cnt">

      <option value="" disabled>Выберите институт</option>

      <option *ngFor="let institute of institutes" [value]="institute.id">{{ institute.name }}</option>

    </select>

    <div *ngIf="registrationForm.get('institute')?.invalid && (registrationForm.get('institute')?.touched || registrationForm.get('institute')?.dirty)" class="error-message">

      Выберите институт.

    </div>

  </div>

  <div class="textbox-container">

    <label for="payment">Сумма оплаты:</label>

    <select id="payment" formControlName="payment" class="select-input">

      <option value="" disabled>Выберите сумму оплаты</option>

      <option value="5040">1-2 курс: 5040 р</option>

      <option value="2520">3 курс: 2520 р</option>

    </select>

    <div *ngIf="registrationForm.get('payment')?.invalid && (registrationForm.get('payment')?.touched || registrationForm.get('payment')?.dirty)" class="error-message">Поле обязательно для заполнения.</div>

  </div>

  <div class="cnt_button">

    <button type="submit" class="section" [disabled]="registrationForm.invalid">Оплатить</button>

  </div>

</form>

<div *ngIf="showPaymentForm">

  <h2>Форма оплаты</h2>

 

  <div *ngIf="remainingTime > 0" class="error-messagep-pay">

    <p>Оставшееся время для оплаты: {{ remainingTime }} секунд</p>

</div>

  <app-payment [registrationForm]="registrationForm" (paymentSuccess)="onPaymentSuccess()"></app-payment>

</div>

В форме если поля не валидны отображаются сообщения, которые помогают пользователю решить проблему И если какое-то поле не валидно, то кнопка оплатить будет не доступна, если все хорошо, то отобразится форма оплаты.

Для работы с формами в Angular необходимо импортировать соответствующие модули. В вашем компоненте используется ReactiveFormsModule, который позволяет создавать реактивные формы:

В @Component класса RegistrationComponent создается форма с несколькими полями и проверяется валидация полей :

Для каждого поля формы добавлены валидаторы, которые проверяют, выполнены ли определенные условия. Например, Validators.required для обязательных полей и пользовательские валидаторы (nameValidator, passwordStrengthValidator, и т.д.) для своих условий:

Метод onRegister, который вызывается при отправке формы. Внутри этого метода проверяется валидность формы и выполняются запросы на резервирование мест и проверку существования email:

Если форма регистрации с полями валидная, то мы отображаем форму для оплаты и запускаем таймер, занимаем место для секции.

Шаблон формы оплаты:

<form [formGroup]="paymentForm" (ngSubmit)="onPay()" class="container_registration">

    <div class="textbox-container">

      <label for="cardNumber">Номер карты:</label>

      <input

          id="cardNumber"

          formControlName="cardNumber"

          class="input_cnt"

          (input)="formatCardNumber($event)"

          placeholder="XXXX XXXX XXXX XXXX" />

      <div *ngIf="cardNumber?.invalid && (cardNumber?.touched || cardNumber?.dirty)" class="error-message">

        <div *ngIf="cardNumber?.errors?.['required']">Это поле обязательно.</div>

        <div *ngIf="cardNumber?.errors?.['pattern'] || cardNumber?.errors?.['invalidCardNumber']">Некорректный номер карты.</div>

      </div>

    </div>

 

    <div class="textbox-container">

      <label for="expiryDate">Срок действия:</label>

      <input

          id="expiryDate"

          formControlName="expiryDate"

          class="input_cnt"

          (input)="formatExpiryDate($event)"

          placeholder="MM/YY" />

      <div *ngIf="expiryDate?.invalid && (expiryDate?.touched || expiryDate?.dirty)" class="error-message">

        <div *ngIf="expiryDate?.errors?.['required']">Это поле обязательно.</div>

        <div *ngIf="expiryDate?.errors?.['pattern']">Некорректная дата. Используйте формат MM/YY.</div>

      </div>

    </div>

 

    <div class="textbox-container">

      <label for="cvv">CVV:</label>

      <input id="cvv" formControlName="cvv" type="password" class="input_cnt" />

      <div *ngIf="cvv?.invalid && (cvv?.touched || cvv?.dirty)" class="error-message">

        <div *ngIf="cvv?.errors?.['required']">Это поле обязательно.</div>

        <div *ngIf="cvv?.errors?.['pattern']">Некорректный CVV. Введите 3 цифры.</div>

      </div>

    </div>

 

    <div class="cnt_button">

      <button type="submit" class="pay">Оплатить</button>

    </div>

  </form>

  1. Валидация: Каждое поле имеет свою логику валидации, которая проверяет наличие значений и их соответствие определенным шаблонам. Используются как встроенные валидаторы (Validators.required, Validators.pattern), так и кастомные валидаторы (например, для проверки номера карты).

Для валидации номера карты у меня создан алгоритм Луна:

Для формы регистрации используем данные методы в сервисе, для работы с базой данных:

Сервисы — это так же обычные класссы. Нам нужно в конструктор класса инжектировать HTTP объект, и добавить декоратор Injectable, необходимый для работы сервиса. Для удобства создадим переменную apiUrl, которая содержит URL-адрес API, с которым будет взаимодействовать сервис. В данном случае это адрес локального сервера (localhost) и конечная точка для пользователей (/students)

submitStudent(student: Student): Observable<any> { return this.http.post(this.apiUrl, student).pipe( catchError(err => { console.error('Ошибка при отправке студента', err); return of(null); }) ); }

Отправляет данные студента на сервер, чтобы создать нового студента. Метод принимает объект student типа Student. this.http.post(this.apiUrl, student): отправляет POST-запрос на указанный apiUrl (например,http: //localhost:3000/students) с данными студента в теле запроса.

RxJS Pipeline:

  • pipe: Метод позволяет обрабатывать ответ или ошибку.

  • catchError: Если возникнет ошибка при отправке запроса, она будет перехвачена. В этом случае в консоль выводится сообщение об ошибке, и возвращается of(null), что позволяет продолжить выполнение без прерывания.

checkEmailExists(email: string): Observable<boolean> { return this.http.get<Student[]>(`${this.apiUrl}?email=${email}`).pipe( map(students => students.length > 0), catchError(() => of(false)) ); }

Проверяет существует ли введенный пользователь в базе данных. Метод принимает email как строку. this.http.get<Student[]>(${this.apiUrl}?email=${email}): отправляет GET-запрос с параметром email на сервер. Это вернет список студентов с указанным email.

  • RxJS Pipeline:

    • map: Параметр students содержит массив объектов Student. Функция проверяет, есть ли в массиве элементы, и возвращает true, если email существует, или false, если не существует.

    • catchError: В случае ошибки (например, при проблемах с сетью) метод вернет false.

uniqueEmailValidator(): AsyncValidatorFn {

return (control: AbstractControl): Observable<ValidationErrors | null> => {

const email = control.value;

if (!email) {

return of(null); // Если поле пустое, возвращаем null для валидации

}

return this.checkEmailExists(email).pipe(

map(exists => (exists ? { emailExists: true } : null)),

catchError(() => of(null)) // Возвращаем null в случае ошибки

);

};

}uniqueEmailValidator(): AsyncValidatorFn {

return (control: AbstractControl): Observable<ValidationErrors | null> => {

const email = control.value;

if (!email) {

return of(null); // Если поле пустое, возвращаем null для валидации

}

return this.checkEmailExists(email).pipe(

map(exists => (exists ? { emailExists: true } : null)),

catchError(() => of(null)) // Возвращаем null в случае ошибки

);

};

}

Асинхронный валидатор для проверки существования email в рамках реактивной формы.

  • В первой части метода проверяется, существует ли значение email. Если поле пустое (т.е., пользователь ничего не ввел), метод возвращает of(null), что означает отсутствие ошибки валидации. Это важно, чтобы избежать лишних запросов к серверу для пустых полей.

  • Если email не пустой, метод вызывает this.checkEmailExists(email), которая возвращает Observable<boolean>. Этот метод выполняет HTTP-запрос к API, чтобы проверить, существует ли указанный email в базе данных.

Если все корректно создаем и заносим данные в базу данных json файл. Используя метод

Теперь форма авторизации студента:

Шаблон авторизации

<app-header></app-header>

<div class="login-container">

    <div class="login-block">

      <h1>Введите свои данные</h1>

      <form [formGroup]="form" (ngSubmit)="onSubmit()">

        <div class="form-group" [ngClass]="{'has-error': form.get('email')?.invalid && form.get('email')?.touched}">

          <div class="input-group">

            <span class="input-group-addon"><i class="fa fa-user ti-user"></i></span>

            <input type="text" class="form-control" placeholder="Введите почту" formControlName="email">

          </div>

          <span class="form-help-text" *ngIf="form.get('email')?.invalid && form.get('email')?.touched">

            <span *ngIf="form.get('email')?.errors?.['required']">Email не может быть пустым.</span>

            <span *ngIf="form.get('email')?.errors?.['email']">Введите корректный email.</span>

          </span>

        </div>

 

        <div class="form-group" [ngClass]="{'has-error': form.get('password')?.invalid && form.get('password')?.touched}">

          <div class="input-group">

            <span class="input-group-addon"><i class="fa fa-lock ti-unlock"></i></span>

            <input [type]="showPassword ? 'text' : 'password'" class="form-control" placeholder="Введите пароль" formControlName="password">

            <span class="password-icon" (click)="showPassword = !showPassword">

              <i [ngClass]="showPassword ? 'fa fa-eye' : 'fa fa-eye-slash'"></i>

            </span>

          </div>

          <span class="form-help-text" *ngIf="form.get('password')?.invalid && form.get('password')?.touched">

            <span *ngIf="form.get('password')?.errors?.['required']">Пароль не может быть пустым.</span>

            <span *ngIf="form.get('password')?.errors?.['minlength']">Пароль должен содержать минимум 8 символов.</span>

          </span>

        </div>

 

        <button class="btn btn-primary" type="submit" [disabled]="form.invalid">Войти</button>

      </form>

      <div class="login-links">

        <p class="text-center">Еще нет аккаунта? <a class="txt-brand" href="#">Регистрируйся</a></p>

      </div>

    </div>

  </div>

  <app-footer></app-footer>

В методе ngOnInit создается реактивная форма с двумя полями: email и password. Они имеют различные валидаторы для проверки на пустоту и формат email.

При отправке формы вызывается метод onSubmit, который выполняет следующие действия:

  1. Проверяет, является ли форма валидной.

  2. Если форма валидна, вызывается метод login из AuthService, передавая email и пароль.

  3. После этого следует подписка на результат (response) вызова метода login:

    1. В случае успешного входа пользователя перенаправляют на страницу студента.

    2. Если вход не удался, пользователю отображается сообщение об ошибке.

Рассмотрим Сервис авторизации:

private apiUrl = 'http://localhost:3000/students';

Этот URL служит для указания конечной точки API, которая отвечает за студентов. Он используется в методе авторизации, чтобы отправить запрос на сервер и получить список студентов для проверки введенных учетных данных.

Метод login:

  1. Выполняет GET-запрос к API для получения списка студентов.

  2. Ищет пользователя с переданными email и паролем.

  3. Если пользователь найден, сохраняет информацию о нем в localStorage, обновляет текущего пользователя BehaviorSubject, и возвращает данные пользователя.

  4. Если пользователь не найден или происходит ошибка, возвращает null.

Аналогично реализована форма авторизации преподавателей и администратора:

Соседние файлы в предмете Web технологии