typescript – Cómo cubrir lista de valores en select Angular 8

He estado mirando este tutorial: https://www.javatpoint.com/angular-spring-crud-example,
pero no he encontrado forma de cubrir valores select al realizar una petición de una API REST.

Os comparto los siguientes códigos fuente:

add-employee.component.html

   <div class="form-group">
          <label for="department">{{'employeeDepartment' | translate }}</label>
          <select class="form-control" formControlName="employee_department" data-toggle="tooltip"
                  data-placement="right" title="{{'employeeDepartment' | translate }}">
            <option value="null">{{'SelectDepartment' | translate }}</option>
            <option value="B-Tech">B-Tech</option>
            <option value="BCA">BCA</option>
            <option value="MCA">MCA</option>
            <option value="M-Tech">M-Tech</option>
          </select>
          <span *ngIf=" employeeDepartment.errors.required">{{'ErrorEmployeeDepartment' | translate }}</span>
        </div>

        <div class="form-group">
          <label for="location">{{'employeeLocation' | translate }}</label>
          <select class="form-control" formControlName="employee_location" data-toggle="tooltip"
                  data-placement="right" title="{{'employeeLocation' | translate }}">
            <option value="null">{{'SelectLocation' | translate }}</option>
            <option value="B-Tech">B-Tech</option>
            <option value="BCA">BCA</option>
            <option value="MCA">MCA</option>
            <option value="M-Tech">M-Tech</option>
          </select>
          <span *ngIf=" employeeDepartment.errors.required">{{'ErrorEmployeeLocation' | translate }}</span>
        </div>

add-employee.component.ts

import { Component, OnInit } from "@angular/core";
import {HttpClientService, Employee, Department, Location, ItemSet, Item} from '../service/httpclient.service';
import { Router } from '@angular/router';
import {FormControl,FormGroup,Validators} from '@angular/forms';

@Component({
  selector: "app-add-employee",
  templateUrl: "./add-employee.component.html",
  styleUrls: ("./add-employee.component.css")
})
export class AddEmployeeComponent implements OnInit {
  employee: Employee = new Employee();
  showSpinner: any;

  constructor(private httpClientService: HttpClientService,
    private router: Router) {}

  employee: Employee = new Employee();
  submitted = false;

  ngOnInit() {
    this.submitted = false;
  }

  employeesaveform = new FormGroup({
    employee_name:new FormControl('' , (Validators.required , Validators.minLength(10) ) ),
    employee_last:new FormControl('' , (Validators.required , Validators.minLength(10) ) ),
    employee_nif:new FormControl('' , (Validators.required , Validators.minLength(9) ) ),
    employee_department: new FormControl('' , Validators.required),
    employee_location: new FormControl('' , Validators.required),
    employee_chief: new FormControl(),
    employee_itemset: new FormControl(),
    employee_item: new FormControl(),
    employee_registerdate: new FormControl(),
    employee_shutdate: new FormControl()
  });

  saveEmployee(saveEmployee){
    this.employee = new Employee();
    this.employee.employeeName = this.employeeName.value;
    this.employee.employeeLastNames = this.employeeLastNames.value;
    this.employee.employeeNIF = this.employeeNIF.value;
    this.employee.department.departmentId = this.employeeDepartment.value;
    this.employee.location.locationId = this.employeeLocation.value;
    this.employee.employeeChief.employeeId = this.employeeChief.value;
    this.employee.itemSet.itemSetId = this.employeeItemSet.value;
    this.employee.item.itemId = this.employeeItem.value;
    this.employee.employeeRegisterDate = this.employeeRegisterDate.value;
    this.employee.employeeShutDate = this.employeeShutDate.value;

    this.submitted = true;
    this.createEmployee();
  }

  get employeeName(){
    return this.employeesaveform.get('employee_name');
  }

  get employeeLastNames(){
    return this.employeesaveform.get('employee_last');
  }

  get employeeNIF(){
    return this.employeesaveform.get('employee_nif');
  }

  get employeeDepartment(){
    return this.employeesaveform.get('employee_department');
  }

  get employeeLocation(){
    return this.employeesaveform.get('employee_location');
  }

  get employeeChief(){
    return this.employeesaveform.get('employee_chief');
  }

  get employeeItemSet(){
    return this.employeesaveform.get('employee_itemset');
  }

  get employeeItem(){
    return this.employeesaveform.get('employee_item');
  }

  get employeeRegisterDate(){
    return this.employeesaveform.get('employee_registerdate');
  }

  get employeeShutDate(){
    return this.employeesaveform.get('employee_shutdate');
  }


  addEmployeeForm(){
    this.submitted=false;
    this.employeesaveform.reset();
  }

  createEmployee(): void {
    console.debug(this.employee);
    this.httpClientService.createEmployee(this.employee).subscribe(data => {
      alert("Employee created successfully.");
      this.router.navigate((''))
    });
  }
}

httpclient.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

export class Department {
  constructor(
    public departmentId: string,
    public departmentName: string,
    public headquarters: Headquarters
  ) {}
}

export class Location {
    public locationId: number;
    public department: Department;
    public locationAbbreviation: string;
    public locationDescription: string;
}

@Injectable({
  providedIn: 'root'
})
export class HttpClientService {
  constructor(private httpClient: HttpClient) {}

  getDepartments() {
    return this.httpClient.get<Department()>('http://localhost:9898/xxxxxx/v1/departmentmanage/departments');
  }

  public deleteDepartment(department) {
    return this.httpClient.delete<Department>(
      'http://localhost:9898/xxxxxx/v1/departmentmanage/department' + '/' + department.departmentId
    );
  }

  public createDepartment(department) {
    return this.httpClient.post<Department>(
      'http://localhost:9898/xxxxxx/v1/departmentmanage/department',
      department
    );
  }

  public updateDepartment(department) {
    return this.httpClient.put<Department>(
      'http://localhost:9898/xxxxxx/v1/departmentmanage/departments' + '/' + department.departmentId,
      department
    );
  }

  getLocations() {
    return this.httpClient.get<Location()>('http://localhost:9898/xxxxxx/v1/locationmanage/locations');
  }

  public deleteLocation(location) {
    return this.httpClient.delete<Location>(
      'http://localhost:9898/xxxxxx/v1/locationmanage/location' + '/' + location.locationId
    );
  }

  public createLocation(location) {
    return this.httpClient.post<Location>(
      'http://localhost:9898/xxxxxx/v1/locationmanage/location',
      location
    );
  }

  public updateLocation(location) {
    return this.httpClient.put<Location>(
      'http://localhost:9898/xxxxxx/v1/locationmanage/locations' + '/' + location.locationId,
      location
    );
  }

Otras preguntas similares: https://stackoverflow.com/questions/43042481/angular2-how-to-get-data-using-query-params-from-dropdown-selection, https://stackoverflow.com/questions/27982320/fill-select-element-using-angular-based-on-query-string-parameter, https://stackoverflow.com/questions/38950494/how-to-show-table-information-with-select-option-in-angular

El objetivo es que en el formulario de añadir salga un despegable con todos los valores extraídos del GET, para así cubrir las FKs obligatorias de la BD de MySQL.

Alguna solución, tanto para HTML como para el archivo ts, por favor?

Muchas gracias! 🙂

Angular – is it good practice using output event emitters directly in the template?

Normally in Angular I am used to treating html events that lead to component output firing in the manner like in the example:

//component:

@Output()
imageHoverEnter = new EventEmitter<void>();

...

onImageHoverEnter() {
  this.imageHoverEnter.emit();
}
//template:

<div>
  <img src="https://stackoverflow.com/..." (mouseenter)="onImageHoverEnter()">
</div>

The reason for having a separate method that protects the @Output being used has to do with my already old habit of separating controller and view logic and not having stuff leaking through. Which can help with automatic testing among others.

However I have seen various examples, including from Google’s own documentation (Angular Material) which use @Output emitters directly in the template:

<div>
  <img src="https://stackoverflow.com/..." (mouseenter)="imageHoverEnter.emit()">
</div>

Moreover if we’re looking at @Input() fields they are being used directly in the template most of the time.

Now I am tempted of doing the exact same thing and ditching the “function that invokes a function” approach (in the cases where there are no other side effects obviously) and I see no reason not doing this, besides me not being used to look at a controller and find it emptier than usual and having to look in the template for certain logic parts.

Are there any big drawbacks to doing things like this?

state – React one-way data binding vs Angular two-way data binding

After hours of reading blog posts, I understand that React has one-way data binding, and Angular has two-way. But I don’t actually know what that means….

React

import { useState } from 'react';
import Switch from "./switch";

function App() {
  const (value, setValue) = useState(false);
  return (
    <Switch
      isOn={value}
      handleToggle={() => setValue(!value)}
    />
  );
}

Angular

import { Component } from '@angular/core';

@Component({
  selector: 'app',
  template: `
    <switch (ngModel)="value" (ngModelChange)="value = $event"></switch>
  `,
})
export class AppComponent {
  value = false;
}

Those look functionally identical to me.

What’s actually the difference between the data bindings?

Notei no chrome devTools que minha aplicação (Angular) está fazendo muitos requests. O que pode estar errado?

//SERVICE
import { Injectable } from ‘@angular/core’;
import { AngularFirestore, AngularFirestoreCollection } from ‘@angular/fire/firestore’;
import { Produto } from ‘../model/produto’;
//import * as rxjs from ‘rxjs’
import { filter, map, reduce, tap, toArray, share,take } from ‘rxjs/operators/’

@Injectable({
providedIn: ‘root’
})
export class ProductService {
productCollection: AngularFirestoreCollection
constructor(private afire: AngularFirestore) {
this.productCollection = this.afire.collection(‘products’);
}

getAllProduct() {
return this.productCollection.snapshotChanges()
.pipe(
map(changes =>
changes.map(a => {
let data = a.payload.doc.data();
let id = a.payload.doc.id
return { id, …data }
})),
take(1),
share()
)
}

getProducts(id) {
return this.afire.doc(‘products/’ + id).valueChanges();
}

addProduct(prod: Produto) {
return this.productCollection.add(prod)
/{
nomeProduto: prod.nomeProduto,
quantidadeEstoque: prod.quantidadeEstoque,
categoria: prod.categoria,
minimoEstoque: prod.minimoEstoque,
tipo: prod.tipo,
descontinuado: prod.descontinuado
}
/

}
getProductByName(name: string) {
// return this.afire.collection(‘products’, ref => ref.where(‘nomeProduto’, ‘==’, name)).valueChanges()
return this.afire.collection(‘products’).valueChanges()
.pipe(
map(prods => {
if (name != "") {
return prods.filter(p => p.nomeProduto.toLowerCase().includes(name.toLowerCase()))
}else{
return null
}
}))

}

update(produto: Produto, key: string) {
this.afire.doc(‘products/’ + key).update(produto)
}
}

//PRODUCT-LIST COMPONENT
import { Component, OnInit, Input } from ‘@angular/core’;
import { Produto } from ‘src/app/model/produto’;
import { ProductService } from ‘src/app/services/product.service’;
import { Observable } from ‘rxjs’;
import { map, debounceTime, distinctUntilChanged, switchMap, take } from ‘rxjs/operators’;
import { FormControl } from ‘@angular/forms’;
import { THIS_EXPR } from ‘@angular/compiler/src/output/output_ast’;

@Component({
selector: ‘app-product-list’,
templateUrl: ‘./product-list.component.html’,
styleUrls: (‘./product-list.component.scss’)
})
export class ProductListComponent implements OnInit {
products: Observable<Produto()>
searchField: FormControl
prod: Observable<Produto()>
constructor(private service: ProductService) {
this.searchField = new FormControl()
this.prod = this.searchField.valueChanges
.pipe(
debounceTime(400),
distinctUntilChanged(),
switchMap(term => this.service.getProductByName(term))
)
}

ngOnInit(): void {

this.products = this.service.getAllProduct()

}

}

post – Enviar archivo PDF por HTTP (ANGULAR 10)

Estoy tratando de enviar un archivo PDF a una API donde requiero de 4 campos, 3 de ellos todo bien pero cuando intento enviar el PDF me lo reconoce como un Array del Input-Select y no como un archivo, soy nuevo en Angular.

Asi obtengo el archivo en el HTML:

<span class="btn btn-primary btn-block btn-file">
  Subir archivo <input (change)="soliUD( 'mi_archivo', false, $event.target.files )" type="file"></span>

Este es el componente.ts

  soliUD(key: string, over: boolean, archivo: FileList){

Swal.fire({
  icon: 'info',
  text: 'Procesando informacion..',
  allowOutsideClick: false
});
Swal.showLoading();
this.authService.updateDocument(key, over, archivo(0) )
                .subscribe( respuestaHttp => {
                  Swal.fire(
                    '¡Exito!',
                    'Se ha guardado la informacion',
                    'success'
                  )
                  console.log(respuestaHttp);
                }, (err) =>{
                  console.log(err);
                })


}

Este es mi servicio.ts

  updateDocument(key: string, over: boolean, file: File){
const arrDocument = {
  token: localStorage.getItem('token'),
  overwrite: over,
  file: file,
  file_key: key
}

return this.httpCliente.post(
  `${this.urlTest}/api/company/user/document/upload`,
  arrDocument
).pipe(
  map( respuesta => {
    return respuesta
  })
);}  

En el servicio y en el componente ya lo he intentado con

const formData: FormData = new FormData(); 
formData.append('file', file, file.name);
formData.append('token', localStorage.getItem('token'));
formData.append('Key', key);
formData.append('overwrite', over);

return this.httpCliente.post(
  `${this.urlTest}/api/company/user/document/upload`,
  formData
).pipe(
  map( respuesta => {
    return respuesta
  })
);}  

Pero el FormData se queda vacio, lo inicializo en el constructor o ngOnInit y nada..

typescript – Por que los datos de mi hijo component aparecen vacios Angular

Hola tengo un componente padre y un componente hijo, el cual le coloco datos a traves de un @Input() al hijo, pero cuando hago un imprimo en mi ngOnInit o mi ngAfterViewInit los datos me aparecen como un arreglo vacio, pero en mi html o despues de un SetTimeOut si me aparecen datos. A que se debe esto? Este es mi codigo:

export class SidebarComponent implements OnInit, AfterViewInit {
  @Input() data: Data();
  constructor() { 
    console.log(data) // Da como resultado ()
}
  ngOnInit(): void { 
    console.log(data) // Da como resultado ()
}
  ngAfterViewInit() {
    console.log(data) // Da como resultado ()
    setTimeout(() => {
    console.log(data) // Da como resultado mi objeto
    },2000);
  }
  
} 

Aqui esta como envio la data en el componente padre

<app-sidebar (data)="data"></app-sidebar>

architecture – Angular multiple templates

I try to be short:

I want to build a SaaS which will provide ecommerce solutions for customers. One of the main problems is that I need to build multiple templates as per example:

  • one template have:

    ------ header ------
    ------ menu --------
    ---------5x5 -------  (grid of products)
    ------ footer ------
    
  • another template have:

    ------- header -----
    ------- menu -------
    ---sidebar + 3x3----  (left sidebar + grid of products)
    ------ footer ------
    

I have no idea how to build an arhitecture for a solution like that, because:

    1. based on Customer Admin Panel, where he will choose the template 1 or 2, the ShopApp must be loaded with the selected template;
    1. based on point 1), result that when the client (the buyer) will access the ShopApp, one template must be preloaded (the selected by admin)

Because the ShopApp will be builded on Angular 10+, how can I divide these templates? I thought at a solution, but I don’t know if is a good example:

  • FOR TEMPLATES (display/hide/alignment of sections in page)
    • reused components (and dumb) with data sources
    • one TemplateComponent for each template which will load these dumb components.
    • each template have a global style (buttons, forms configurated by the client, etc) and send it as @Input to the child components (reused components)
    • if I have 100 templates, then my ShopApp will load pointless all other 99 templates, so I need that use lazy loading here.

The ShopApp requests will be so:

    1. loading main.js
    1. httpsRequest – getAppTemplate() + load default styles of the template
    1. based on 2) answer, load the template + load personalized styles
    1. populate the components (httprequests for data sources)

I think first 3 steps must be done early, because until these, the webpage will be empty (no data rendered).

at point 2), foreach template, the application will have a default style (I found something to how I can lazy load styles per templates):
– styles1.css, styles2.css, styles3.css – one of them will be injected in the app module

Thanks. Feel free to comment, tell me if this is a wrong section to post the question here and if you can, recommand a website, a forum or a ggroup where I can ask all these.

angularjs – Lista en angular muestra solo [object Object]

tengo un problema a la hora de mostrar un select con varios titulos. Estoy trabajando con angular y no lo manejo muy a la perfección ya que hace poco que he empezado.Lo que he hecho es dos base de datos una de episodios de star wars y otra de personajes. Un ejemplo seria id:2 titulo: Return of the Jedi y el año de estreno. Y con el personaje tengo su id:1, nombre: Luke SkyWalker episodio:2. El atributo de personaje episodio:2 hace referencia a la id de los episodios. Y en el apartado de personajes quiero hacer un select donde se vean todos los titulos de los episodios disponibles para que cuando el usuario quiera añadir un personaje seleccione este episodio.

En el typescript de personajes hago el import de Episodios y hago el siguiente código:

ngOnInit(): void{
    this.ServeApi.obtenerPersonajes().subscribe((personajes: Personaje()) => {
      this.lPersonajes = personajes;
      this.ServeApi.obtenerEpisodios().subscribe((episodios: Episodio()) => {
        this.lEpisodio = episodio;
        var j=0;
        var i=0;
        for(i=0;i<this.lPersonajes.length;i++)
        {
          for(j=0;j<this.lEpisodios.length;j++)
          {
              if(this.lEpisodios(j).id == parseInt(this.lPersonajes(i).numEpisodio))
              {
                this.lPersonajes(i).numEpisodio = this.lEpisodio(j).titulo;
              }
          }
          j=0;
        }
      });
    });
  }

Y luego en el html hago esto :

<select class="custom-select" name="numEpisodio" ((ngModel))=personajeSeleccionado.numEpisodio style="max-width: 30%;">
   <option *ngFor="let a of lPersonajes">{{ a }}</option>
</select>

Pero en los selects de la web muestra un monton de (object Object) y no se a que deberia ser

angular9 – Angular 10 Cannot find a differ supporting object ‘[object Object]’ of type ‘object’. NgFor only supports binding to Iterables such as Arrays

I’m trying to invoke my REST API to get some data and display them in html page Using Angular 10.
here’s my my http service.

public findUsers(page: number, size: number): Observable<User()> {
    return this.http.get<User()>(AUTH_API+`users?page=${page}&size=${size}`, httpOptions);
}

And here’s my service’s call.

  export class AccountComponent implements OnInit {
  paginator: MatPaginator = {} as MatPaginator;
  loaded: boolean;
  users: User();
  data:any;

  constructor(private accountSerive: AccountService) { }

  ngOnInit(): void {
    this.paginator.pageIndex = 0;
        this.paginator.pageSize = 20;
    this.getUsers();
  }
  getUsers() {
    this.data = this.accountSerive.findUsers(this.paginator.pageIndex, this.paginator.pageSize)
    .subscribe((data) => {
      this.users = data;
      this.loaded = true; 
    });
  }

}

Here’s my HTML code

 <tr *ngFor="let user of users" >
            <td>{{user.name}}</td>
            <td>{{user.username}}</td>
            <td>{{user.email}}</td>
            <td>{{user.password}}</td>
            <td>{{user.role}}</td>
          </tr>

And finally my user Model

    export interface User {
    email: string;
    password: string;
    userName: string;
    roles: (Role); 

}
export interface Role {
    name: string; 
    
}