حفظ الملفات على Firebase Storage - والتحقق من أبعاد الصورة

التثبيت:
npm i angular/fire

 يمكننا حفظ أي ملف نحتاجه على الـ Firebase Storage من خلال الأكواد التالية:

https://stackoverflow.com/questions/68939014/angularfiremodule-and-angularfiredatabasemodule-not-being-found-in-angular-fire

بداية لا بد من استدعاء المكتبات التالية في الـ app.module.ts

import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireStorageModule } from '@angular/fire/compat/storage';
imports: [
    AngularFireStorageModule,
    AngularFireModule.initializeApp({
      apiKey: "",
      authDomain: "",
      databaseURL: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: ""
    }),
    AppRoutingModule,
    BrowserModule,
    FormsModule,
    HttpClientModule,
    MaterialModule,
    ReactiveFormsModule,
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => getAuth()),
    provideDatabase(() => getDatabase()),
    provideFirestore(() => getFirestore()),
    BrowserAnimationsModule,
    LayoutModule,
    MatToolbarModule,
    MatButtonModule,
    MatSidenavModule,
    MatIconModule,
    MatListModule,
    TranslateModule.forRoot({
      defaultLanguage: 'ar',
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })
  ],


في الملف التابع للمكون يكون الكود بهذا الشكل:

import { Component, ElementRef, Inject, Injectable, ViewChild } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar';
import { onValue } from 'firebase/database';
import { User } from 'src/app/models/user';
import { FirebaseService } from 'src/app/services/firebase.service';
import { LocalStorageService } from 'src/app/services/local-storage.service';
import { AngularFireStorage } from '@angular/fire/compat/storage';
import { concatWith, finalize, Observable } from 'rxjs';
import { TaskState } from 'firebase/firestore';
import { UploadTask, UploadTaskSnapshot } from '@angular/fire/compat/storage/interfaces';




@Component({
  selector: 'app-personal-profile',
  templateUrl: './personal-profile.component.html',
  styleUrls: ['./personal-profile.component.scss']
})

export class PersonalProfileComponent {
  @ViewChild('hiddenPictube') hiddenPictube: ElementRef<HTMLInputElement>;

  path: any;
  onlineImage: any;
  imageBaseRef: any;
  imageRef: any;

  //Storage Variables
  uploadPercent: Observable<number>;
  downloadURL: Observable<string>;
  profileUrl: any;

  personalInfoForm = this._formBuilder.group({
    firstName: ['', Validators.required],
    lastName: ['', Validators.required],
    titleJob: ['', Validators.required],
    enTitleJob: ['', Validators.required],
    employeeId: ['', Validators.required],
    email: ['', Validators.compose([Validators.required, Validators.email])],
    mobileNo: ['', Validators.required],
  });

  constructor(private storage: AngularFireStorage) {
  }

  ngOnInit(): void {
  }

  updateInfo() {
    if (this.personalInfoForm.status === "VALID") {
      this.user.picture = (this.hiddenPictube.nativeElement.value.trim() !== "") ? this.hiddenPictube.nativeElement.value : this.user.picture;
      this.editPersonalInfo = !this.editPersonalInfo;
      this.user.createdAt = this.user.createdAt;
      this.user.modifiedAt = this.user.modifiedAt;
      this.user.createdBy = this.user.email;
      this.user.modifiedBy = this.user.email;
      this.firebaseService.updateUser(this.user.id, this.user);
      this.hiddenPictube.nativeElement.value = "";
    } else {
      this.openSnackBar("يرجى التحقق من أنّ جميع المدخلات صحيحة!", "إغلاق");
    }
  }

  async upload(event: any) {
    const file = event.target.files[0];
    const filePath = "profiles/profile_" + this.user.id + "." + file.name.split('.')[1];
    const fileRef = this.storage.ref(filePath);
    const task = this.storage.upload(filePath, file);

    // observe percentage changes
    this.uploadPercent = task.percentageChanges();

    // get notified when the download URL is available
    task.snapshotChanges().pipe(
      finalize(() => {
        this.downloadURL = fileRef.getDownloadURL();
      })).subscribe();
  }

  uploadChange() {
    this.user.picture = this.hiddenPictube.nativeElement.value;
    this.firebaseService.updateUser(this.user.id, this.user);
  }
}


أما كود الـ HTML للمكون فهو كالتالي:

<div class="padding">
  <div class="row container w-100 d-flex justify-content-center">
    <div class="col-xl-12 col-md-12">
      <div class="card user-card-full">
        <div class="row m-l-0 m-r-0">
          <div class="col-sm-4 bg-c-lite-green user-profile">
            <div class="card-block text-center text-white">
              <div class="m-b-25">
                <img #userPicture [src]="user.picture" style="width: 150px;height: 150px;" class="mg-thumbnail mb-4 mt-2 rounded-circle" [alt]="user.firstName">
                <input [style]="(editPersonalInfo == false)? 'display:none;':'display:block;'" type="file" (change)="upload($event);" accept="*.png.jpg">

                <!-- <i (click)="uploadImage()" [style]="(editPersonalInfo == false)? 'display:none;':'display:block;'"
                  class="mdi mdi-image-edit feather icon-edit m-t-10 f-25" [matTooltip]="'تغيير الصورة'"></i> -->
              </div>

              <input ngModel #hiddenPictube (change)="uploadChange()" type="hidden" [value]="downloadURL | async">

              <h6 class="f-w-600">{{ user.firstName + ' '+ user.lastName }}</h6>
              <p>{{ user.titleJob }}</p>
              <!-- <a (click)="uploadChange()">fgfdgdfg</a> -->

              <i (click)="updateInfo();"
                [class]="(editPersonalInfo == false)? 'mdi mdi-square-edit-outline feather icon-edit m-t-10 f-25' : 'mdi mdi-content-save feather icon-edit m-t-10 f-25'"
                [matTooltip]="(editPersonalInfo == false)? 'تحرير المعلومات':'حفظ التغييرات'"></i>
              <!-- {{ editPersonalInfo }} -->
            </div>
          </div>
          <div class="col-sm-8">
            <form [formGroup]="personalInfoForm">
              <div class="card-block">
                <h6 class="m-b-20 p-b-5 b-b-default f-w-600">المعلومات الشخصية</h6>
                <div class="row">
                  <div class="col-sm-6  mt-2">
                    <p class="m-b-10 f-w-600"
                      [style]="(editPersonalInfo == false)? 'display: block;': 'display: none;'">
                      الاسم
                      الأول</p>
                    <h6 [style]="(editPersonalInfo == false)? 'display: inline;': 'display: none;'"
                      class="text-muted f-w-400">{{user.firstName}}</h6>
                    <mat-form-field [style]="(editPersonalInfo == false)? 'display: none;': 'display: inline;'">
                      <mat-label>الاسم الأول</mat-label>
                      <input matInput formControlName="firstName" [(ngModel)]="user.firstName" #first_name
                        maxlength="50" placeholder="مثلاً: محمد" required>
                      <mat-error align="start" *ngIf="personalInfoForm.controls['firstName'].hasError('required')">
                        هذا الحقل إلزامي
                      </mat-error>
                      <!-- <mat-hint align="start"><strong>اسمك هذا سيكون معتمداً برمجياً</strong>
                                            </mat-hint> -->
                      <mat-hint align="end">{{first_name.value.length}} / 50</mat-hint>
                    </mat-form-field>
                  </div>
                  <div class="col-sm-6  mt-2">
                    <p class="m-b-10 f-w-600"
                      [style]="(editPersonalInfo == false)? 'display: block;': 'display: none;'">
                      الاسم
                      الأخير</p>
                    <h6 [style]="(editPersonalInfo == false)? 'display: inline;': 'display: none;'"
                      class="text-muted f-w-400">{{user.lastName}}</h6>
                    <mat-form-field [style]="(editPersonalInfo == false)? 'display: none;': 'display: inline;'">
                      <mat-label>الاسم الأخير</mat-label>
                      <input matInput formControlName="lastName" [(ngModel)]="user.lastName" #last_name maxlength="50"
                        placeholder="مثلاً: السالم" required>
                      <!-- <mat-hint align="start"><strong>اسمك هذا سيكون معتمداً برمجياً</strong>
                                            </mat-hint> -->
                      <mat-error align="start" *ngIf="personalInfoForm.controls['lastName'].hasError('required')">
                        هذا الحقل إلزامي
                      </mat-error>
                      <mat-hint align="end">{{last_name.value.length}} / 50</mat-hint>
                    </mat-form-field>
                  </div>
                  <div class="col-sm-6  mt-2">
                    <p class="m-b-10 f-w-600"
                      [style]="(editPersonalInfo == false)? 'display: block;': 'display: none;'">
                      المسمى الوظيفي</p>
                    <h6 [style]="(editPersonalInfo == false)? 'display: inline;': 'display: none;'"
                      class="text-muted f-w-400">{{user.titleJob}}</h6>
                    <mat-form-field [style]="(editPersonalInfo == false)? 'display: none;': 'display: inline;'">
                      <mat-label>المسمى الوظيفي</mat-label>
                      <input formControlName="titleJob" [(ngModel)]="user.titleJob" matInput #title_job maxlength="50"
                        placeholder="مثلاً: مهندس برمجيات" required>
                      <!-- <mat-hint align="start"><strong>يرجى كتابة مسماك الوظيفي</strong>
                                            </mat-hint> -->
                      <mat-error align="start" *ngIf="personalInfoForm.controls['titleJob'].hasError('required')">
                        هذا الحقل إلزامي
                      </mat-error>
                      <mat-hint align="end">{{title_job.value.length}} / 50</mat-hint>
                    </mat-form-field>
                  </div>
                  <div class="col-sm-6  mt-2">
                    <p class="m-b-10 f-w-600"
                      [style]="(editPersonalInfo == false)? 'display: block;': 'display: none;'">
                      المسمى الوظيفي بالإنجليزي</p>
                    <h6 [style]="(editPersonalInfo == false)? 'display: inline;': 'display: none;'"
                      class="text-muted f-w-400">{{user.enTitleJob}}</h6>
                    <mat-form-field [style]="(editPersonalInfo == false)? 'display: none;': 'display: inline;'">
                      <mat-label>المسمى الوظيفي بالإنجليزي</mat-label>
                      <input formControlName="enTitleJob" [(ngModel)]="user.enTitleJob" matInput #en_title_job
                        maxlength="50" placeholder="مثلاً: Software Engineer" required>
                      <mat-error align="start" *ngIf="personalInfoForm.controls['enTitleJob'].hasError('required')">
                        هذا الحقل إلزامي
                      </mat-error>
                      <!-- <mat-hint align="start"><strong>يرجى كتابة مسماك الوظيفي بالإنجليزي</strong>
                                            </mat-hint> -->
                      <mat-hint align="end">{{en_title_job.value.length}} / 50</mat-hint>
                    </mat-form-field>
                  </div>
                  <div class="col-sm-6 mt-2">
                    <p class="m-b-10 f-w-600"
                      [style]="(editPersonalInfo == false)? 'display: block;': 'display: none;'">
                      الرقم
                      الوظيفي</p>
                    <h6 [style]="(editPersonalInfo == false)? 'display: inline;': 'display: none;'"
                      class="text-muted f-w-400">{{user.employeeId}}</h6>
                    <mat-form-field [style]="(editPersonalInfo == false)? 'display: none;': 'display: inline;'">
                      <mat-label>الرقم الوظيفي</mat-label>
                      <input formControlName="employeeId" [(ngModel)]="user.employeeId" matInput #employee_id
                        type="text"
                        onKeyPress="if(this.value.length==10) return false; return event.charCode >= 48 && event.charCode <= 57"
                        placeholder="مثلاً: 1115" required>
                      <mat-error align="start" *ngIf="personalInfoForm.controls['employeeId'].hasError('required')">
                        هذا الحقل إلزامي
                      </mat-error>
                      <!-- <mat-hint align="start"><strong>يرجى إدخال الرقم الوظيفي بدقة</strong>
                                            </mat-hint> -->
                      <mat-hint align="end">{{employee_id.value.length}} / 10</mat-hint>
                    </mat-form-field>
                  </div>
                </div>
                <h6 class="m-b-20 m-t-40 p-b-5 b-b-default f-w-600">معلومات الاتصال</h6>
                <div class="row">
                  <div class="col-sm-6 mt-2">
                    <p class="m-b-10 f-w-600"
                      [style]="(editPersonalInfo == false)? 'display: block;': 'display: none;'">
                      البريد الإلكتروني</p>
                    <h6 [style]="(editPersonalInfo == false)? 'display: inline;': 'display: none;'"
                      class="text-muted f-w-400">{{user.email}}</h6>
                    <mat-form-field [style]="(editPersonalInfo == false)? 'display: none;': 'display: inline;'">
                      <mat-label>البريد الإلكتروني</mat-label>
                      <input formControlName="email" matInput [(ngModel)]="user.email" #email type="email"
                        maxlength="50" placeholder="مثلاً: abc@abc.com" required>
                      <mat-error align="start" *ngIf="personalInfoForm.controls['email'].hasError('required')">
                        هذا الحقل إلزامي
                      </mat-error>
                      <mat-error
                        *ngIf="personalInfoForm.controls['email'].hasError('email') && !personalInfoForm.controls['email'].hasError('required')">
                        البريد الإلكتروني المدخل غير صحيح!
                      </mat-error>
                      <!-- <mat-hint align="start"><strong>يرجى إدخال بريد صحيح</strong> </mat-hint> -->
                      <mat-hint align="end">{{email.value.length}} / 50</mat-hint>
                    </mat-form-field>
                  </div>
                  <div class="col-sm-6 mt-2">
                    <p class="m-b-10 f-w-600"
                      [style]="(editPersonalInfo == false)? 'display: block;': 'display: none;'">
                      رقم
                      الجوال</p>
                    <h6 [style]="(editPersonalInfo == false)? 'display: inline;': 'display: none;'"
                      class="text-muted f-w-400">{{user.mobileNo}}</h6>
                    <mat-form-field [style]="(editPersonalInfo == false)? 'display: none;': 'display: inline;'">
                      <mat-label>رقم الجوال</mat-label>
                      <input formControlName="mobileNo" matInput [(ngModel)]="user.mobileNo" #mobile_no type="text"
                        onKeyPress="if(this.value.length==10) return false; return event.charCode >= 48 && event.charCode <= 57"
                        placeholder="مثلاً: 0508532127" required>
                      <mat-error align="start" *ngIf="personalInfoForm.controls['mobileNo'].hasError('required')">
                        هذا الحقل إلزامي
                      </mat-error>
                      <!-- <mat-hint align="start"><strong>يرجى كتابة الأرقام فقط</strong> </mat-hint> -->
                      <mat-hint align="end">{{mobile_no.value.length}} / 10</mat-hint>
                    </mat-form-field>
                  </div>
                  <div class="col-sm-6 mt-2">
                    <p class="m-b-10 f-w-600">إنشاء الحساب</p>
                    <h6 class="text-muted f-w-400">{{user.createdAt | date:'dd-MM-yyyy - hh:mm a'}}</h6>
                  </div>
                  <div class="col-sm-6 mt-2">
                    <p class="m-b-10 f-w-600">آخر نشاط</p>
                    <h6 class="text-muted f-w-400">{{user.lastActive | date: 'dd-MM-yyyy - hh:mm a'}}</h6>
                  </div>
                </div>
              </div>
            </form>

          </div>
        </div>
      </div>
    </div>
  </div>
</div>


الرجع:

https://github.com/angular/angularfire/blob/master/docs/storage/storage.md


https://github.com/angular/angularfire/blob/master/docs/version-7-upgrade.md


المشاكل:

مشكلة:   node_modules/@angular/fire/compat/firestore/interfaces.d.ts:29:33

    29 export interface DocumentChange<T> extends firebase.firestore.DocumentChange {


الحل: https://stackoverflow.com/questions/73281199/error-when-importing-angularfiredatabasemodule

https://github.com/angular/angularfire/issues/3290#issuecomment-1323837275




------------------------------------------------------------------------------------------

الطريقة الأفضل كالتالي:



التثبيتات الهامة:
https://www.npmjs.com/package/angularfire2


------------------------------------------------------------------------------------------


الطريقة الأفضل

كود الـ ts

import { Injectable } from '@angular/core';
import { Observable, finalize } from 'rxjs';
import { AngularFireStorage, AngularFireStorageReference, AngularFireUploadTask } from '@angular/fire/compat/storage';


@Injectable({
  providedIn: 'root'
})
export class UpluadFilesService {
  uploadProgress: Observable<any>;
  ref: AngularFireStorageReference;
  task: AngularFireUploadTask;
  downloadURL: Observable<string>;

  constructor(
    private afStorage: AngularFireStorage,
  ) { }

  async uploadSlow(event: any) {
    let role = '' !== '' && '' !== '';
    if (role) {
      const id = "cv_" + "Abdullah" + "_" + 'Alsalem';//Math.random().toString(36).substring(2)
      const file = event.target.files[0];
      const filePath = "cv/" + id + "." + file.name.split('.')[1];
      this.ref = this.afStorage.ref(filePath);
      this.task = this.ref.put(file);
      this.uploadProgress = this.task.percentageChanges();
      this.downloadURL = new Observable;
      this.downloadURL = await this.ref.getDownloadURL();
      // this.employmentApplication.cv = this.cv.nativeElement.value;
    } else {
      let message = 'hi';
      alert(message);
    }
  }

  uploadFast(event: any, theObject: any,
    uploadProgress: Observable<any>, downloadURL: Observable<string>
  ): Observable<string> {
    const file = event.target.files[0];
    const filePath = "cv/cv_" + (Math.floor(Math.random() * (150 - 1) + 1)) + "." + file.name.split('.')[1];
    const fileRef = this.afStorage.ref(filePath);
    const task = this.afStorage.upload(filePath, file);

    // observe percentage changes
    uploadProgress = task.percentageChanges();

    // get notified when the download URL is available
    task.snapshotChanges().pipe(
      finalize(() => {
        downloadURL = fileRef.getDownloadURL();
        // theObject.cv = refHtml.nativeElement.value;
      })
    )
      .subscribe();
    return downloadURL;
  }
}


كود الـ HTML

                   <div class="col-12 col-md-6 mt-3">
                        <div class="mt-4 row">
                            <mat-label class="label col-4">{{'LABELS.ATTACH_CV' | translate}} : </mat-label>
                            <!-- <button (click)="fileUpload.click()"></button> -->
                            <input id="input-file-id" (change)="uploadFile($event)" class="col-8"
                                accept=".pdf, .doc, .docx, |file/*" type="file" />
                            <div class="col-12 mt-2 progress" *ngIf="!(downloadURL | async)">
                                <div class="progress-bar progress-bar-striped bg-success" role="progressbar"
                                    [style.width]="(uploadProgress | async) + '%'"
                                    [attr.aria-valuenow]="(uploadProgress | async)" aria-valuemin="0"
                                    aria-valuemax="100">
                                </div>
                            </div>
                            <b class="mt-2" *ngIf="!(downloadURL | async)">{{'WARNING.DELAYED_UPLOAD' | translate}}</b>
                            <span class="col-12 mt-2" *ngIf="!(downloadURL | async)">{{('WARNING.UPLOAD_FILE' |
                                translate) + ' {' + (uploadProgress |
                                async) + '% }' }}</span>
                            <input ngModel #cv type="hidden" [value]="downloadURL | async">

                            <div *ngIf="downloadURL | async; let downloadSrc" class="col-12 mt-2 alert alert-info"
                                role="alert">
                                {{'SUCCESS.FILE_UPLOADED' | translate}}: <a [href]="downloadSrc"
                                    target="_blank">{{'BUTTONS.VIEW_FILE' | translate}}</a><br>
                                <!-- <input (change)="updateCvValue(downloadSrc)"
                                     type="text" [value]="downloadSrc"> -->
                            </div>

                            <mat-error align="start" *ngIf="secondFormGroup.controls['cv_file'].hasError('required')">
                                {{'ERRORS.REQUIRED' | translate}}
                            </mat-error>


                        </div>
                    </div>


والأهم وبدونه لن يعمل الكود مطلقاً إعدادات الـ app.module.ts




آخر ما توصلتُ له من إنتاجية:

//-----------------------------------upload files--------------------------

  async uploadForDragDrop(files: any) {
    const generateName = this.maintenanceTicket.subject + " (" + this.maintenanceTicket.request_type + ")";//Math.random().toString(36).substring(2)
    const file = files[0];
    const filePath = "maintenancesTickets/" + generateName + "." + file.name.split('.')[1];
    const fileRef = this.storage.ref(filePath);
    const task = this.storage.upload(filePath, file);

    const fileSizeInMB = file.size / (1024 * 1024); // Convert file size to MB

    if (fileSizeInMB <= 10) {
      // File size is less than or equal to 10 MB, accept the file
      // Perform further processing or upload the file
      // observe percentage changes
      this.uploadPercent = task.percentageChanges();

      // get notified when the download URL is available
      task.snapshotChanges().pipe(
        finalize(() => {
          this.downloadURL = fileRef.getDownloadURL();
          this.waitingDownloadFile = true;
          setTimeout(() => {
            let attachment = new MaintenancesAttachment();
            attachment.maintenance = this.maintenanceTicket;
            attachment.name = generateName;
            attachment.type = file.type;
            this.extension = file.name.split('.')[1].toLocaleUpperCase();
            attachment.extension = file.name.split('.')[1].toLocaleUpperCase();
            attachment.file_size = fileSizeInMB;
            attachment.url = this.hiddenFile.nativeElement.value.trim();
            attachment.star = false;

            this.maintenancesAttachmentsService.postItem(attachment, true, this.uploadFile.nativeElement.value, '');
          }, 5000); // Delay of 2000 milliseconds (2 seconds)
          this.waitingDownloadFile = false;
        })).subscribe(a => {
          // this.maintenanceTicket.photo = (this.hiddenFile.nativeElement.value.trim() !== "") ? this.hiddenPictube.nativeElement.value : this.employee.photo;
        });
    } else {
      this.snackBarService.openSnackBar(this.size10LessThan.nativeElement.value, '');
    }
  }
  async uploadFiles(event: any) {
    const generateName = this.maintenanceTicket.subject + " (" + this.maintenanceTicket.request_type + ")";//Math.random().toString(36).substring(2)
    const file = event.target.files[0];
    const filePath = "maintenancesTickets/" + generateName + "." + file.name.split('.')[1];
    const fileRef = this.storage.ref(filePath);
    const task = this.storage.upload(filePath, file);

    const fileSizeInMB = file.size / (1024 * 1024); // Convert file size to MB

    if (fileSizeInMB <= 10) {
      // File size is less than or equal to 10 MB, accept the file
      // Perform further processing or upload the file
      // observe percentage changes
      this.uploadPercent = task.percentageChanges();

      // get notified when the download URL is available
      task.snapshotChanges().pipe(
        finalize(() => {
          this.downloadURL = fileRef.getDownloadURL();
          this.waitingDownloadFile = true;
          setTimeout(() => {
            let attachment = new MaintenancesAttachment();
            attachment.maintenance = this.maintenanceTicket;
            attachment.name = generateName;
            attachment.type = file.type;
            this.extension = file.name.split('.')[1].toLocaleUpperCase();
            attachment.extension = file.name.split('.')[1].toLocaleUpperCase();
            attachment.file_size = fileSizeInMB;
            attachment.url = this.hiddenFile.nativeElement.value.trim();
            attachment.star = false;

            this.maintenancesAttachmentsService.postItem(attachment, true, this.uploadFile.nativeElement.value, '');
            this.waitingDownloadFile = false;
          }, 5000); // Delay of 2000 milliseconds (2 seconds)
        })).subscribe(a => {

          // this.maintenanceTicket.photo = (this.hiddenFile.nativeElement.value.trim() !== "") ? this.hiddenPictube.nativeElement.value : this.employee.photo;
        });
    } else {
      this.snackBarService.openSnackBar(this.size10LessThan.nativeElement.value, '');
    }
  }


للتحقق من أبعاد الصور:

HTML

<input ngModel #hiddenFile type="hidden" [value]="downloadURL | async">
<div class="col-12 col-md-12 mt-3">
<mat-label class="mt-2"><strong>{{'LABELS.IMAGE' | translate}}</strong></mat-label>
<div (click)="fileInput.click()" (drop)="onDrop($event);" (dragover)="onDragOver($event);"
  class="p-3 cursor-pointer mt-3 w-100 bg-for-attachments alyahya-text-primary border-for-attachments">
  <div class="absolute">
    <div class="d-flex justify-content-center">
      <span class="block text-gray-400 font-normal">
                <i class="mdi mdi-folder-open f-25 text-blue-700"></i> {{'BUTTONS.DRAG_AND_DROP' |
          translate}} <br>
            <mat-progress-bar class="mt-3"
                [matTooltip]="'LOADING.PLEASE_WAIT_5_SECONDS' | translate"
             *ngIf="waitingDownloadFile" mode="buffer"></mat-progress-bar>

    <span *ngIf="extension === 'PDF'"><a
             [href]="downloadURL | async">{{'BUTTONS.VIEW_FILE'
                | translate}}</a></span>
        <br>
        <img *ngIf="extension === 'PNG' || extension === 'JPG' || extension === 'JPEG'"
      style="height: 288px; width: auto;" [src]="downloadURL | async" alt="">

       </span>
                            </div>
                        </div>
                        <!-- opacity-0 -->
                        <input #fileInput (change)="onFileSelected($event);uploadImage($event);" accept=".png, .jpg"
                            style="display: none !important;" type="file" class="h-full w-full w-100" class="d-block"
                            name="">
                    </div>

TS

_validateDimensions: boolean =  false;

  validateDimensions(width: number, height: number) {
    const minWidth = 1920; // Set your minimum width requirement
    const minHeight = 345; // Set your minimum height requirement
 
    if (width !== minWidth || height !== minHeight) {      
     this._validateDimensions = false;
    } else {
      // Image dimensions are valid, proceed with upload logic (if applicable)
      this._validateDimensions = true;
    }
  }

  onFileSelected(event: any) {
    const file = event.target.files[0];
    const reader = new FileReader();
 
    reader.onload = (e: any) => {
      const img = new Image();
      img.onload = () => {
        this.validateDimensions(img.width, img.height); // Call validation function
      };
      img.src = e.target.result;
    };
 
    reader.readAsDataURL(file);
  }


  async uploadImage(event: any) {
    setTimeout(()=>{
      if(this._validateDimensions){
        this.extension = event.target.files[0].name.split('.')[1].toLocaleUpperCase();
        const generateName = event.target.files[0].name;//Math.random().toString(36).substring(2)
        const file = event.target.files[0];
   
        if (this.extension === 'PNG' || this.extension === 'JPG') {
          const filePath = "main-carousel/" + generateName;
          const fileRef = this.storage.ref(filePath);
          const task = this.storage.upload(filePath, file);
          const fileSizeInMB = file.size / (1024 * 1024); // Convert file size to MB
   
          if (fileSizeInMB <= 10) {
            this.uploadPercent = task.percentageChanges();
            task.snapshotChanges().pipe(
              finalize(() => {
                this.downloadURL = fileRef.getDownloadURL();
                this.waitingDownloadFile = true;
                setTimeout(() => {
                  this.item.image = this.hiddenFile.nativeElement.value.trim();
                  this.waitingDownloadFile = false;
                }, 5000); // Delay of 2000 milliseconds (2 seconds)
              })).subscribe(a => {
              });
          } else {
            this.snackBarService.openSnackBar(this.translateService.instant('WARNING.SIZE_10_LESS_THAN'), '');
          }
        }
        else {
          this.snackBarService.openSnackBar(this.translateService.instant('ERRORS.REJECT_EXTENSION'), '');
        }
      }else{
        this.snackBarService.openSnackBar('يجب أن تكون أبعاد الصورة 1920×345','')
      }    
    }, 1000);
  }












































تعليقات

المشاركات الشائعة من هذه المدونة

ngx-extended-pdf-viewer

how to getting access token for https://fcm.googleapis.com/v1/projects/al-ayahya-co/messages:send for angular and backend nestjs

طريقة تفعيل زر Inline Keyboard في Telegram Bot