La modifica di un prodotto è una sintesi del lavoro svolto fin qui. La pagina di modifica prevede la visualizzazione di un form già popolato e in questo verrà in soccorso quanto già visto per la visualizzazione di un singolo prodotto, mentre per la creazione del form la lezione precedente contiene tutto ciò che serve. Il dialogo con il backend PHP sarà fatto come sempre con i service.
Come prima cosa procediamo con la creazione del nuovo component:
ng g component prodotti/update-product
Registriamo il component nel modulo principale dell'applicazione:
import { UpdateProductComponent } from './products/update-product/update-product.component';
@NgModule({
declarations: [
..
UpdateProductComponent,
L'accesso alla pagina di modifica avviene dalla lista dei prodotti tramite pulsante di edit sul quale abbiamo definito un link contenente la rotta e il parametro id
del record da modificare:
<a [routerLink]="['/update',product.id]" class='btn btn-info'>
<span class='glyphicon glyphicon-edit'></span> Edit
</a>
Questo significa che dovremo aggiornare il modulo delle rotte:
import {UpdateProductComponent} from './products/update-
const routes:Routes=[
..
{path:'update/:id', component:UpdateProductComponent},
Veniamo al component: la lista degli import sarà lunga ma priva di novità: i due service, la classe per le categorie, i moduli del form e i moduli delle rotte per la lettura del parametro e del ritorno alla lista ad aggiornamento completato. Anche il decoratore non presenta novità:
@Component({
selector: 'app-update-product',
templateUrl: './update-product.component.html',
styleUrls: ['./update-product.component.css'],
providers: [ProductService, CategoryService]
})
Il component avrà 3 proprietà: l'id
del prodotto da modificare, il form e la lista delle categorie per la SELECT
:
update_product_form: FormGroup;
product_id:number;
categories: Category[];
Al costruttore passiamo i moduli:
constructor(
private route:ActivatedRoute,
private router:Router,
private productService: ProductService,
private categoryService: CategoryService,
private formBuilder: FormBuilder
)
E implementiamo i controlli sui form:
{
this.update_product_form = this.formBuilder.group({
name: ["", Validators.required],
price: ["", Validators.required],
description: ["", Validators.required],
category_id: ["", Validators.required]
});
}
All'OnInit
del component dovremo leggere il parametro dal routing, caricare i dati del singolo prodotto per cui disponiamo già del metodo nel service e, infine, caricare la lista delle categorie. Quindi, per lettura del parametro:
this.route.params.subscribe(params => {
this.product_id=params['id'];
});
Caricare i dati del singolo record presenta una novità: appena otteniamo la risposta del server andiamo ad impostare i value
dei campi di input del form con i dati ricevuti in modo che appaia già precompilato:
this.productService.readOneProduct(this.product_id)
.subscribe(product => {
this.update_product_form.patchValue({
name: product.nome,
nome: product.prezzo,
descrizione: product.descrizione,
category_id: product.categoria_id
});
});
Infine, ecco la lista delle categorie:
this.categoryService.readCategories()
.subscribe(categories => this.categories=categories['records']);
}
Il template HTML sarà simile a quello per l'inserimento, pertanto riportiamo le differenze a livello di codice relative alla dichiarazione del form:
<form [formGroup]="update_product_form" (ngSubmit)="updateProduct()">
Cambia il formGroup
a cui è agganciato e il metodo da chiamare nella classe del component. Di conseguenza c'è una piccola variazione nell'if
della gestione degli errori:
<div *ngIf="update_product_form.get('nome').touched && update_product_form.get('nome').hasError('required')" class="alert alert-danger">
Ultima novità nel loop che genera le option della SELECT
con l'aggiunta dell'attributo selected
:
<select formControlName="category_id" name='category_id' class='form-control'>
<option
*ngFor="let category of categories"
[selected]="category_id==category.id"
value='{{category.id}}'>
{{category.nome}}
</option>
</select>
Aggiungiamo il metodo per l'UPDATE al service dei prodotti: lo schema da seguire è quello per l'INSERT con la novità che è il metodo della chiamata che in accordo con il nostro backend restituirà put
:
updateProduct(product): Observable{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.put(
"http://localhost/phprest/api/v1/prodotti/",
product,
options
).map(res => res.json());
}
Possiamo quindi aggiungere al component il metodo per l'UPDATE che chiamerà a sua volta il service:
this.productService.updateProduct(this.update_product_form.value)
.subscribe(
product => {
this.router.navigateByUrl('/home');
}
);
}
Anche in questo caso, una volta aggiornato il record ritorniamo alla lista dei prodotti.