Uploading multiple images using angular and send them to api - html

im using angular as front-end and trying to upload 2 images and then send them as a string to OCR API,
here is my code
let reader:FileReader = new FileReader();
let image = new Image();
var file;
for (var i = 0; i < imgFile.target.files.length; i++){
file = imgFile.target.files[i]
reader.onload = (e: any) => {
image.src = e.target.result;
image.onload = rs => {
//console.log(reader.result);
this.fileString = image.src;
};
};
reader.readAsDataURL(file)
}
the problem is I cant send the files to the API , as I don't know how to get the image data as a string to send them together
what can I do?

Plenty of examples, but you need an upload service with the correct Backend URL to the API, this one can do any file type. Just filter out the file type you dont want in the upload function
POST /upload Upload a file
GET /files Get a list of files
GET /files/[filename] Download a file
src/app/upload.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpRequest, HttpEvent } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class UploadService {
private serverUrl = 'http://localhost:8080';
constructor(private httpClient: HttpClient) { }
upload(file: File): Observable<HttpEvent<any>> {
const formData: FormData = new FormData();
formData.append('file', file);
const request = new HttpRequest('POST', `${this.serverUrl}/upload`, formData, {
reportProgress: true,
responseType: 'json'
});
return this.httpClient.request(request);
}
getFiles(): Observable<any> {
return this.httpClient.get(`${this.serverUrl}/files`);
}
}
Create and MultiImageUploadComponent.ts
import { Component, OnInit } from '#angular/core';
import { UploadService } from 'src/app/upload.service';
import { HttpEventType, HttpResponse } from '#angular/common/http';
import { Observable } from 'rxjs';
export class UploadComponent implements OnInit {
selectedFiles: FileList;
progressInfos = [];
message = '';
fileInfos: Observable<any>;
constructor(private uploadService: UploadService) { }
}
ngOnInit(): void {
this.fileInfos = this.uploadService.getFiles();
}
selectFiles(e): void {
this.progressInfos = [];
this.selectedFiles = e.target.files;
}
uploadFiles(): void {
this.message = '';
for (let i = 0; i < this.selectedFiles.length; i++) {
this.upload(i, this.selectedFiles[i]);
}
}
upload(idx, file): void {
this.progressInfos[idx] = { value: 0, fileName: file.name };
this.uploadService.upload(file).subscribe(
event => {
if (event.type === HttpEventType.UploadProgress) {
this.progressInfos[idx].value = Math.round(100 * event.loaded / event.total);
} else if (event instanceof HttpResponse) {
this.fileInfos = this.uploadService.getFiles();
}
},
err => {
this.progressInfos[idx].value = 0;
this.message = 'Could not upload the file:' + file.name;
});
}
your HTML template
<div *ngFor="let progressInfo of progressInfos" class="mb-2">
<span>{{ progressInfo.fileName }}</span>
<div class="progress">
<div
class="progress-bar progress-bar-info progress-bar-striped"
role="progressbar"
attr.aria-valuenow="{{ progressInfo.value }}"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: progressInfo.value + '%' }"
>
{{ progressInfo.value }}%
</div>
</div>
</div>
<label class="btn btn-default">
<input type="file" multiple (change)="selectFiles($event)" />
</label>
<button
class="btn btn-success"
[disabled]="!selectedFiles"
(click)="uploadFiles()">
Upload
</button>
<div class="alert alert-light" role="alert">{{ message }}</div>
<div class="card">
<div class="card-header">List of Files</div>
<ul
class="list-group list-group-flush"
*ngFor="let file of fileInfos | async"
>
<li class="list-group-item">
{{ file.name }}
</li>
</ul>
</div>
You can call it like so from your app, where <app-upload> is your directive/component above
<h1>{{ title }}</h1>
<div class="container">
<app-upload></app-upload>
</div>
Make sure the OCR API is wired up to the services to invoke & POST

Related

Best way to implement a pageable to Angular Project

I have products in my database and I have created controller on my backend app that I tested and works really good, so now I need to implement that to my frontend. I have product.component.ts file that looks like this
import { Component, OnInit } from "#angular/core";
import { FormControl, FormGroup } from "#angular/forms";
import { debounceTime, switchMap } from "rxjs";
import { ProductService } from "./product.service";
#Component({
selector: 'app-product',
templateUrl: './product.component.html'
})
export class ProductComponent implements OnInit {
products: any[] = [];
productSearchForm!: FormGroup;
page: number = 0;
size: number = 4;
constructor(
private productService: ProductService
) { }
loadMore() {
this.page = this.page+1;
this.productSearchForm.get('searchTerm')?.valueChanges
.pipe(
debounceTime(500),
switchMap(value => {
return this.productService.searchByTermPageable(value, this.page, this.size);
})
).subscribe(data => {
this.products = data;
}, error => {
console.log(error);
// this.products = [];
});
}
ngOnInit(): void {
this.initializeForm();
this.productSearchForm.get('searchTerm')?.valueChanges
.pipe(
debounceTime(500),
switchMap(value => {
return this.productService.searchByTermPageable(value, this.page, this.size);
})
).subscribe(data => {
this.products = data;
}, error => {
console.log(error);
// this.products = [];
});
}
private initializeForm(): void {
this.productSearchForm = new FormGroup({
searchTerm: new FormControl(null)
});
}
}
searchTerm is a query param that is used to find products with name starting with that term. I call function from file product.service.ts that looks like this
import { HttpClient } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import { environment } from "src/environments/environment";
#Injectable({ providedIn: 'root'})
export class ProductService {
constructor(private httpClient: HttpClient) { }
searchByTerm(searchTerm: string): Observable<any> {
const url = `${environment.apiUrl}product/search/by-name-or-desc?term=${searchTerm}`;
return this.httpClient.get(url);
}
searchByTermPageable(searchTerm: string, page: number, size: number): Observable<any> {
const url = `${environment.apiUrl}product/search/by-name-or-desc?term=${searchTerm}&page=${page}&size=${size}`;
return this.httpClient.get(url);
}
}
When I click the button load more I want to load next 4 products from database, but keep the first 4 products on my html page, so what is the best way to do this? This is my html page, and also I am using Bulma as my css framework
<div class="mt-5">
<form>
<div class="field" [formGroup]="productSearchForm">
<div class="control has-icons-left">
<input class="input" type="text" formControlName="searchTerm" placeholder="Find products">
<span class="icon is-small is-left">
<i class="fas fa-search"></i>
</span>
</div>
</div>
<hr />
</form>
</div>
<div class="columns">
<div class="column" *ngFor="let product of products">
<div class="card">
<div class="card-content">
<div class="media">
<div class="media-content">
<p class="title is-4">{{ product.name }}</p>
<p class="subtitle is-6">{{ product.category?.name}}</p>
</div>
</div>
<div class="content">
{{ product.description }}
</div>
</div>
</div>
</div>
</div>
<button type="button" class="button is-primary" (click)="loadMore()">Load more...</button>
You can to have a new function in your service that return the elements of the page plus the other elements search. If you has a function that return the paginate elements
searchByTermPageable(search:string,page:number,size:number)
{
...
}
Some like
product:any[]=[] //define an empty array where you store the product
searchOld:string=null //and a variable to store the search
getData(search:string,page:number,size:number)
{
if (search!=this.searchOld) //if is a new search
{
this.searchOld=search
this.product=[]
}
return this.searchByTermPageable(search,page,size).pipe(
map((res:any[])=>[...this.product,...res]), //concat the before store product
tap((res:any[])=>{
this.product=res //store in the product the new array
})
)
}
Allow you some like
<div *ngFor="let product of product$|async">
{{product.name}}
</div>
<button (click)="more()">more</button>
pageIndex:number=-1;
product$:Observable<any[]>
more()
{
this.pageIndex++
this.product$=this.dataService.getData("",this.pageIndex,4)
}
The other solution is search all the product and simple use slice pipe
<div *ngFor="let product of allProduct$|async |slice:0:(index+1)*pageSize">
{{product.name}}
</div>
<button (click)="index=index+1">more</button>
a litle stackblitz

Angular App deosn't dispay data from table althgouh the exist in the console

One of the most important things to make a website friendly is the response time, and pagination comes for this reason. For example, this bezkoder.com website has hundreds of tutorials, and we don’t want to see all of them at once. Paging means displaying a small number of all, by a page.
here is the class for the "Dossier entity":
export class Dossier {
id?: any;
title?:string;
creationDate?:string;
statusDossier?:string;
documentNumber?:number;
activityTitle?:string;
published?:boolean;
}
This is a kind of server-side paging, where the server sends just a single page at a time. ngx-pagination supports this scenario, so We actually only need to use tutorials and totalItems when working with this library.
This service will use Angular HttpClient to send HTTP requests.
services/dossier.service.ts
import { Injectable } from '#angular/core';
import {HttpClient} from "#angular/common/http";
import {Observable} from "rxjs";
import {Dossier} from "../models/dossier.model";
const baseUrl = 'http://localhost:8080/api/dossiers';
#Injectable({
providedIn: 'root'
})
export class DossierService {
constructor(private http: HttpClient) { }
getAll(params: any): Observable<any> {
return this.http.get<any>(baseUrl, { params });
}
get(id: any): Observable<Dossier> {
return this.http.get(`${baseUrl}/${id}`);
}
create(data: any): Observable<any> {
return this.http.post(baseUrl, data);
}
update(id: any, data: any): Observable<any> {
return this.http.put(`${baseUrl}/${id}`, data);
}
delete(id: any): Observable<any> {
return this.http.delete(`${baseUrl}/${id}`);
}
deleteAll(): Observable<any> {
return this.http.delete(baseUrl);
}
findByTitle(title: any): Observable<Dossier[]> {
return this.http.get<Dossier[]>(`${baseUrl}?title=${title}`);
}
}
We can customize the label displayed on the “previous”/”next” link using previousLabel/nextLabel, and enable “responsive” to hide individual page links on small screens.
For pagination, we’re gonna use DossierService.getAll() methods.
components/dossiers-list/dossiers-list.component.ts
export class DossiersListComponent implements OnInit {
dossiers: Dossier[] = [];
currentDossier: Dossier = {};
currentIndex = -1;
title = '';
page = 1;
count = 0;
pageSize = 3;
pageSizes = [3, 6, 9];
constructor(private dossierService: DossierService) { }
ngOnInit(): void {
this.retrieveDossiers();
}
getRequestParams(searchTitle: string, page: number, pageSize: number): any {
let params: any = {};
if (searchTitle) {
params[`title`] = searchTitle;
}
if (page) {
params[`page`] = page - 1;
}
if (pageSize) {
params[`size`] = pageSize;
}
return params;
}
retrieveDossiers(): void {
const params = this.getRequestParams(this.title, this.page, this.pageSize);
this.dossierService.getAll(params)
.subscribe({
next: (data) => {
const { dossiers, totalItems } = data;
this.dossiers = dossiers;
this.count = totalItems;
console.log(data);
},
error: (err) => {
console.log(err);
}
});
}
handlePageChange(event: number): void {
this.page = event;
this.retrieveDossiers();
}
handlePageSizeChange(event: any): void {
this.pageSize = event.target.value;
this.page = 1;
this.retrieveDossiers();
}
refreshList(): void {
this.retrieveDossiers();
this.currentDossier = {};
this.currentIndex = -1;
}
setActiveTutorial(dossier: Dossier, index: number): void {
this.currentDossier = dossier;
this.currentIndex = index;
}
removeAllDossiers(): void {
this.dossierService.deleteAll()
.subscribe({
next: res => {
console.log(res);
this.refreshList();
},
error: err => {
console.log(err);
}
});
}
searchTitle(): void {
this.page = 1;
this.retrieveDossiers();
}
}
and finally here is the html file:
<div class="list row">
<div class="col-md-8">
<div class="input-group mb-3">
<input
type="text"
class="form-control"
placeholder="Search by title"
[(ngModel)]="title"
/>
<div class="input-group-append">
<button
class="btn btn-outline-secondary"
type="button"
(click)="searchTitle()"
>
Search
</button>
</div>
</div>
</div>
<div class="col-md-12">
<pagination-controls
previousLabel="Prev"
nextLabel="Next"
[responsive]="true"
(pageChange)="handlePageChange($event)"
></pagination-controls>
</div>
<div class="col-md-6">
<h4>Tutorials List</h4>
<ul class="list-group">
<li
class="list-group-item"
*ngFor="
let tutorial of dossiers | paginate : {
itemsPerPage: pageSize,
currentPage: page,
totalItems: count
};
let i = index
"
[class.active]="i == currentIndex"
(click)="setActiveTutorial(tutorial, i)"
>
{{ tutorial.title }}
</li>
</ul>
</div>
<div class="col-md-6">
<!-- <app-tutorial-details-->
<!-- [viewMode]="true"-->
<!-- [cu]="currentDossier"-->
<!-- ></app-tutorial-details>-->
</div>
<div class="mt-3">
<button class="m-3 btn btn-sm btn-danger" (click)="removeAllDossiers()">
Remove All
</button>
Items per Page:
<select (change)="handlePageSizeChange($event)">
<option *ngFor="let size of pageSizes" [ngValue]="size">
{{ size }}
</option>
</select>
</div>
</div>

Trying to implement a checkbox complete into To Do List

Trying to implement a checkbox complete to my To Do List but unsure why it is not working.
Whenever my code compiles down to Javascript I get this error:
" ERROR in src/app/ToDo/todo.component.ts(89,32): error TS2339: Property 'item' does not exist on type 'ToDoComponent'. "
Also i'm unsure why my IDE is saying the task is considered an any statement.
UPDATE:
My console in my browser is displaying this error:
Unexpected closing tag "li". It may happen when the tag has already been closed by another tag.
TypeScript:
import { Component, OnInit, EventEmitter, Output } from '#angular/core';
import { ToDo, IToDo } from './todo.model';
import { HttpClient } from '#angular/common/http';
import { LocalStorageService } from '../localStorageService';
import { ActivatedRoute, Router } from '#angular/router';
import { IUser } from '../login/login.component';
import { ToastService } from '../toast/toast.service';
#Component({
// tslint:disable-next-line: component-selector
selector: 'todolist',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class ToDoComponent implements OnInit {
[x: string]: any;
todos: Array<IToDo> = [];
inputtask = "";
toDoParams = '';
localStorageService: LocalStorageService<IToDo>;
currentUser: IUser;
#Output() update: EventEmitter<any> = new EventEmitter();
constructor(
private http: HttpClient,
private activatedRoute: ActivatedRoute,
private router: Router) {
this.localStorageService = new LocalStorageService('todos');
}
private toastService: ToastService;
async ngOnInit() {
const currentUser = this.localStorageService.getItemsFromLocalStorage('user');
console.log('from todos component', currentUser);
if (currentUser == null) {
await this.router.navigate(['login']);
} else {
// if user is logged in go and find any items from local storage and bind
// to the view
const toDoItems = this.localStorageService.getItemsFromLocalStorage('todos');
if (toDoItems && Array.isArray(toDoItems)) {
this.todos = toDoItems;
}
}
}
addToDo(todo: string, cm?: boolean) {
const td = {
id: null,
task: todo,
completed: cm,
}
if (todo === '') {
alert('You must enter in a task TO DO!')
} else {
this.todos.push(td);
}
this.saveItemsToLocalStorage(this.todos);
}
delete(index: number) {
this.todos.splice(index, 1);
console.log("index", index);
this.saveItemsToLocalStorage(this.todos);
}
clear() {
this.todos = [];
console.log('index', this.todos)
this.saveItemsToLocalStorage(this.todos);
}
getItemsFromLocalStorage(key: string) {
const savedToDo = JSON.parse(localStorage.getItem(key));
console.log('from getItemsFromLocalStorage savedItems', savedToDo);
return this.localStorageService.getItemsFromLocalStorage(key);
return savedToDo;
}
completeItem() {
this.update.emit({
task: this.todos,
changes: {completed: this.task.completed}
});
}
saveItemsToLocalStorage(todos: Array<IToDo>) {
todos = this.sortByID(todos);
return this.localStorageService.saveItemsToLocalStorage(todos);
const savedToDo = localStorage.setItem('todos', JSON.stringify(todos));
console.log('from saveItemsToLocalStorage savedToDos: ', savedToDo);
return savedToDo;
}
sortByID(todos: Array<IToDo>) {
todos.sort((prevToDo: IToDo, presToDo: IToDo) => {
return prevToDo.id > presToDo.id ? 1 : -1;
});
console.log('the sorted ToDos', this.todos);
return this.todos;
}
logout() {
// clear localStorage
this.localStorageService.clearItemFromLocalStorage('user');
// navigate to login page
this.router.navigate(['']);
}
}
HTML Code:
<ul class="list-group">
<li *ngFor="let todo of todos; let i = index"
class="list-group-item shadow p-3 mb-5 bg-white rounded border border-dark rounded" id="myTask">
<div class="todo-item">
{{todo.task}} <button type="button" class="btn btn-danger" (click)="delete()">X</button>
<input type="checkbox" class="todo-checkbox" (click)="completeItem()">
<span class="todo-title" [ngClass]="{'todo-complete': item.completed}">
</li>
</ul>
<span class="todo-title" [ngClass]="{'todo-complete': item.completed}">
Here you are using item which doesn't exist in your typescript file. Did you mean to use todo from your *ngFor ?

How to rerun a ngFor loop after its variable's value has been changed in the component?

I'm trying to make a Github Search app and have used a ngFor loop to display search data. As I type the value the value of UARR changes but no changes are made to the DOM.
Initially also as I enter one character it show the result instantly but subsequent keydowns have no effect on the HTML DOM. I'm confused and looked everywhere for an answer but it was of no avail.
How can I possibly rerun ngFor loop each time the value of uarr changes?
<div class="row">
<div class="col-md-12">
<form>
<div class="form-group">
<input type="text" class="form-control" [(ngModel)]="username" name="username" (keyup)="searchUser()" >
</div>
</form>
</div>
</div>
<div *ngIf="uarr" >
<ul *ngFor="let data of uarr" class="list-unstyled" >
<li>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<a href="#" >
<img class="github-avatar" src="{{data.avatar_url}}" >
</a>
<div class="caption">
<h3 class="text-center">{{ data.login }}</h3>
</div>
</div>
</div>
</li>
</ul>
</div>
The componentcode:
import { Component } from '#angular/core';
import { GithubService } from '../services/git.services';
import { map } from 'rxjs/operators';
//import { user } from '../models/gitusers';
#Component({
selector: 'searchform',
templateUrl: 'search.component.html',
providers:[GithubService]
})
export class SearchformComponent {
users : any;
uarr: any[] = [];
username: string;
// #Output() userUpdated: EventEmitter<user> = new EventEmitter<user>();
constructor(private _githubService: GithubService) {
}
searchUser() {
this._githubService.updateUser(this.username);
console.log(this.username);
this._githubService.getUser().subscribe(user => {
this.users = user.items;
for (var i in this.users) {
this.uarr.push(this.users[i]); }
});
console.log(this.uarr);
}
/*
ngOnInit() {
if (this.user) {
this.user.user = false;
this.getUserInformation();
}
}
getUserInformation() {
if (this.user.userName && this.user.userName.length > 0) {
this._githubService.getUser().subscribe(user => {
this.user.user = user;
// this.userUpdated.emit(this.user);
},
(err) => {
console.log('err:' + err);
this.user.user = false;
},
() => console.log('Done')
);
this._githubService.getRepos().subscribe(repos => {
// console.log(repos);
this.user.repos = repos;
// this.userUpdated.emit(this.user);
},
(err) => {
console.log('err:' + err);
this.user.user = false;
},
() => console.log('Done')
);
}
}*/
}
The Services Code:
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { environment } from '../../environments/environment';
const API_URL = environment.apiUrl;
#Injectable()
export class GithubService {
private userName = "matt";
private client_id = '3198278eb6fb7788fa1e';
private client_secret = 'd6b3cf6265f7997f110ec1450246e7157d055a8f';
constructor(private _http: Http) {
console.log('Github Service Ready.');
}
getUser() {
if (this.userName) {
return this._http.get(API_URL + this.userName + '&client_id=' + this.client_id + '&client_secret=' + this.client_secret)
.pipe(
map(res => res.json()),
catchError(this.handleError));
}
}
getRepos() {
if (this.userName) {
return this._http.get(API_URL + this.userName + '/repos')
.pipe(
map(res => res.json()),
catchError(this.handleError));
}
}
updateUser(username: string) {
this.userName = username;
console.log(this.userName);
}
private handleError(error: any) {
if (error.status === 401) {
return Observable.throw(error.status);
} else {
return Observable.throw(error.status || 'Server error');
}
}
}
Some of the functions in the services are redundant and for future use.
Should I remove the Exception handling code to decrease the size of the app.
Thank You.

What is dispose of null in Angular 4

I am getting "what is dispose of null" when load the page.
I am to get list of data but unable to show those record in view.
Here i added code snippet to understand my requirement
Angular JS Service File
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class PostsService {
data: any = null;
totalDocs: number;
url: any = 'http://localhost:3000/services/';
constructor(private _http: Http) { }
public getPosts() {
return this._http.get(this.url + 'posts')
.map((res: Response) => res.json());
}
}
//End Angular JS Web service*
Node JS code to get data from MongoDB
import { default as Category} from "../models/Category";
import { default as Post} from "../models/Post";
import { Request, Response, NextFunction } from "express";
export let getPostsAPI = (req: Request, res: Response, next: NextFunction) => {
const post: any = req.body;
const cond: any = {};
if (!this.empty(post.kword)) {
*//$text is full text index*
cond.$text = {$search : post.kword};
}
if (!this.empty(post.location)) {
cond.city = {$regex: new RegExp("^" + post.location, "i") };
}
*Counting total number of records and
Here Post is reference of collection, its working fine and generating data as i given bottom of this post.*
Post.count(cond).then(totalDocs => {
Post.find(cond).sort({created_at: -1}).then(result => {
const results = {data: result, totalDocs: totalDocs};
console.log(results);
res.end("" + JSON.stringify(results));
});
});
};
End node JS Code
Angular JS home.component.ts where i am calling web serive to render data in angular view
export class HomeComponent implements OnInit {
results: any = {};
model: any = {};
constructor(private posts: PostsService) {
posts.getPosts().subscribe(res => {
console.log(res.totalDocs); // Showing number of records in console.
this.results = res.data; // this is throwing error.
*//Error is: TypeError: Cannot read property 'dispose' of null*
});
this.model.kword = '';
this.model.location = '';
}
ngOnInit() {
}
}
Template Code
<div class="container">
<app-filter [result]=value (clicked)="searchJob($event)"></app-filter>
<!-- /.row -->
<div class="row" >
<div class="col-sm-10 my-10" *ngFor="let post of results | async">
<div class="card">
<div class="card-body">
<h3 class="mt-1"><a [routerLink]="['/job', post.company, post.title, post._id]">{{ post.title }}</a></h3>
<p class="mt-1" *ngIf="post.company"><span class="badge badge-primary">{{post.company}}</span></p>
<p class="mt-1" *ngIf="post.salary_min">Salary up to: ₹{{post.salary_min}} - ₹{{post.salary_max}}</p>
<p class="mt-1" *ngIf="post.city || post.state">Location: {{post.city}}, <span *ngIf="post.state">{{post.state}}</span></p>
<p class="mt-1" *ngIf="post.description">{{post.description | slice:0:150}}[...]</p>
</div>
</div>
</div>
</div>
<!-- /.row -->
</div>
End Template
JSON DATA WHICH COMING FROM API
{
"data":
[
{
"title":"test title",
"description":"test description"
}
],
"totalRecords":2
}
i attached a screenshot of error.
The async pipe subscribes to an observable for you, so it needs to be fed an observable, you're feeding it the resulting value of an observable, which is why you're seeing this error.
Do it like this instead:
results: Observable<any>;
model: any = {};
constructor(private posts: PostsService) {
this.results = posts.getPosts().map(res => res.data);
this.model.kword = '';
this.model.location = '';
}
Now you're setting the "results" value to the actual observable, and letting async handle the subscription part.