I am trying to develop crud using mean stack. When making HTTP requests, angular works fine, but I only want angular to make post request when the submit button for the reactive form is pressed, but it makes both get and post request to the nodejs/express server automatically. is there any option to make the post only when the form submit button is triggered? Thanks a lot.
pdt: I know is making both requests because I am using morgan in nodejs server.
empleados.component.html
<form [formGroup]="nuevoEmpleado" (submit)="addEmpleado()">
<label>
Nombre:
<input type="text" formControlName="nombre">
</label>
<label>
Apellido:
<input type="text" formControlName="apellido">
</label>
<label>
Cargo:
<input type="text" formControlName="cargo">
</label>
<button type="submit" class="btn btn-primary">Agregar Empleado</button>
</form>
<!--tabla lista de empleados -->
<table class="table table-dark">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Nombre</th>
<th scope="col">Apellido</th>
<th scope="col">Cargo</th>
<th scope="col">acciones</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let empleado of listaEmpleados; let i=index">
<th scope="row">{{ i+1 }}</th>
<td>{{ empleado.nombre }}</td>
<td>{{ empleado.apellido }}</td>
<td>{{ empleado.cargo }}</td>
<td>Eliminar</td>
</tr>
</tbody>
</table>
empleados.components.ts
import { Component, OnInit } from '#angular/core';
import { EmpleadosService } from './empleados.service';
import { FormControl , FormGroup } from '#angular/forms';
import { empleado } from '../interfaces/empleado'
#Component({
selector: 'app-empleados',
templateUrl: './empleados.component.html',
styleUrls: ['./empleados.component.css']
})
export class EmpleadosComponent implements OnInit {
nuevoEmpleado = new FormGroup({
nombre: new FormControl(''),
apellido: new FormControl(''),
cargo: new FormControl('')
});
listaEmpleados: empleado[];
constructor(private empleadosService: EmpleadosService) {}
getListaEmpleados():void{
this.empleadosService.getlistaEmpleados().subscribe(empleados => this.listaEmpleados = empleados);
};
addEmpleado(){
//this.empleadosService.addEmpleado(this.nuevoEmpleado.value).subscribe(res => console.log(res));
if(!this.nuevoEmpleado){
return;
}
this.empleadosService.addEmpleado(this.nuevoEmpleado.value).subscribe(res => console.log(res));
}
ngOnInit(): void {
this.getListaEmpleados();
this.addEmpleado();
}
}
empleados.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { empleado } from '../interfaces/empleado';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class EmpleadosService {
url = 'http://localhost:3000';
constructor(private http: HttpClient) {}
getlistaEmpleados():Observable<empleado[]>{
return this.http.get<empleado[]>(this.url);
}
addEmpleado(nuevoEmpleado):Observable<Object>{
return this.http.post<empleado>(this.url , nuevoEmpleado);
}
}
Related
When we add static data in angular datatable all things work fine, but when we load the data table from an API, the pagination, search, and sorting don't work. And it show's "No data available in table", but data is present in the table, also attaching the images.
Click me to view img
Here is the HTML Code
<table datatable [dtOptions]="dtOptions" class="datatable-init nowrap nk-tb-list nk-tb-ulist">
<thead>
<tr class="nk-tb-item nk-tb-head">
<th class="nk-tb-col nk-tb-col-check">
<div class="custom-control custom-control-sm custom-checkbox notext">
<input type="checkbox" class="custom-control-input" id="uid" />
<label class="custom-control-label" for="uid"></label>
</div>
</th>
<th class="nk-tb-col"><span class="sub-text">Customer Name</span></th>
<th class="nk-tb-col tb-col-mb">
<span class="sub-text">Phone Number</span>
</th>
<th class="nk-tb-col tb-col-md">
<span class="sub-text">CNIC</span>
</th>
<th class="nk-tb-col tb-col-lg">
<span class="sub-text">Joining Date</span>
</th>
<th class="nk-tb-col tb-col-lg">
<span class="sub-text">Expiry Date</span>
</th>
<th class="nk-tb-col tb-col-lg">
<span class="sub-text">Status</span>
</th>
<th class="nk-tb-col nk-tb-col-tools text-end"></th>
</tr>
</thead>
<tbody >
<tr class="nk-tb-item" *ngFor="let user of allUsers">
<td class="nk-tb-col nk-tb-col-check">
<div class="custom-control custom-control-sm custom-checkbox notext">
<input type="checkbox" class="custom-control-input" id="uid1" />
<label class="custom-control-label" for="uid1"></label>
</div>
</td>
<td class="nk-tb-col">
<span>{{user.customerName}}</span>
</td>
<td class="nk-tb-col tb-col-md">
<span>{{user.phoneNumber}}</span>
</td>
<td class="nk-tb-col tb-col-lg">
<span>{{user.CNIC_Number}}</span>
</td>
<td class="nk-tb-col tb-col-lg">
<span class="badge bg-secondary">{{user.Joining_Date}}</span>
</td>
<td class="nk-tb-col tb-col-md">
<span class="badge bg-danger">{{user.Expiry_Date}}</span>
</td>
<td class="nk-tb-col tb-col-md">
<span class="badge bg-success">Active</span>
</td>
<td class="nk-tb-col nk-tb-col-tools">
<ul class="nk-tb-actions gx-1">
<li>
<div class="drodown">
<a href="#" class="dropdown-toggle btn btn-icon btn-trigger" data-bs-toggle="dropdown"><em
class="icon ni ni-more-h"></em></a>
<div class="dropdown-menu dropdown-menu-end">
<ul class="link-list-opt no-bdr">
<li>
<a data-bs-toggle="modal" href="#mViewDetails"><em
class="icon ni ni-eye"></em><span>View
Details</span></a>
</li>
<li>
<a data-bs-toggle="modal" href="#mEditDetails"><em
class="icon ni ni-edit"></em><span>Edit
Details</span></a>
</li>
<li>
<a class="cursor" (click)="Toast.sendReminder()"><em
class="icon ni ni-send"></em><span>Send
Reminder</span></a>
</li>
<li>
<a data-bs-toggle="modal" href="#mChangeStatus"><em
class="icon ni ni-exchange"></em><span>Change Status</span></a>
</li>
<li>
<a href=""><em
class="icon ni ni-delete"></em><span>Delete
User</span></a>
</li>
</ul>
</div>
</div>
</li>
</ul>
</td>
</tr>
<!-- .nk-tb-item -->
</tbody>
</table>
Here is the TS Code
import { Component, OnInit } from '#angular/core';
import { Subject } from 'rxjs';
import { ToastService } from 'src/app/services/toast.service';
import { IDropdownSettings } from 'ng-multiselect-dropdown';
import { UserDetailService } from '../../services/user-detail.service';
import { Inter } from '../../inter';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-view-user',
templateUrl: './view-user.component.html',
styleUrls: ['./view-user.component.css']
})
export class ViewUserComponent implements OnInit {
constructor(public Toast: ToastService,
private userDetails: UserDetailService, private http: HttpClient) {
}
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject<any>();
dropdownList: any = [];
selectedItems = [];
allUsers: Inter[] = [];
dropdownSettings: IDropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
itemsShowLimit: 3,
allowSearchFilter: true
};
dataForTable: any;
fetch() {
this.http.get<any>('http://localhost:3000/user').subscribe(data => {
this.dataForTable = data;
console.log(this.dataForTable);
})
}
ngOnInit(): void {
this.dtOptions = {
pagingType: 'full_numbers',
language: {
searchPlaceholder: "Type Into Search"
}
};
this.fetch();
this.dropdownList = [
{ item_id: 1, item_text: 'Naan Shami' },
{ item_id: 2, item_text: 'Chicken Manchurian' },
{ item_id: 3, item_text: 'Pune' },
{ item_id: 4, item_text: 'Navsari' },
{ item_id: 5, item_text: 'New Delhi' }
];
this.get()
}
get() {
this.userDetails.get().subscribe((data) => {
this.allUsers = data;
});
}
delete(id: number) {
this.userDetails.delete(id).subscribe((data) => {
this.allUsers = this.allUsers.filter((_) => _.id !== id);
});
}
}
Here is the users.module.ts Code
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { UsersRoutingModule } from './users-routing.module';
import { AddUserComponent } from './components/add-user/add-user.component';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { ViewUserComponent } from './components/view-user/view-user.component';
import { DataTablesModule } from 'angular-datatables';
import { NgMultiSelectDropDownModule } from 'ng-multiselect-dropdown';
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
AddUserComponent,
ViewUserComponent
],
imports: [
CommonModule,
UsersRoutingModule,
NgbModule,
FormsModule,
ReactiveFormsModule,
DataTablesModule,
HttpClientModule,
NgMultiSelectDropDownModule.forRoot(),
]
})
export class UsersModule { }
Please add the following.
this.dtTrigger.next();
It will update the rows in the table.
your component, declare the following
#ViewChild(DataTableDirective)
dtElement: DataTableDirective;
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
after you pull your data from the service
this.serviceName.getData().subscribe((data) => {
// ADD THIS
this.dtTrigger.next();
}, (err) => {
})
For more please refer to the answer.
This is what I have tried? I wanted to call the deleteDebt() function in the code. But I can't pass the function to const Debt. (Outside the class) How can I do that?
Here I want to pass the props.debt._id through the function. Because I want to delete the particular row in the table with it's _id.
const Debt = props => (
<tr>
<td>{props.debt.fullName}</td>
<td>{props.debt.damount}</td>
<td>
<button className="btn btn-danger btn-info " type="delete" onClick={() => this.deleteDebtor(props.debt._id)}>DELETE</button>
</td>
</tr>
)
export default class profile extends Component {
constructor(props) {
super(props);
this.deleteDebtor = this.deleteDebtor.bind(this);
this.state = {
fullName: '',
damount: '',
users: []
}
}
this is where i get data from the database.
componentDidMount() {
axios.get('url')
.then(response => {
this.setState({ users: response.data.data });
})
.catch(function (error) {
console.log(error);
})
}
this is where i make the table.
UserList() {
// console.log(this.state.users);
return this.state.users.map(function (currentDebt, i) {
return <Debt debt={currentDebt} key={i} />;
}
}
this is the deleteDebt() function.
deleteDebtor(data) {
axios.delete('url' + data)
}
this is rendering part
render() {
return (
<React.Fragment>
<div >
<table } >
<thead>
<tr>
<th>Name </th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{this.UserList()}
</tbody>
</table>
</div>
</React.Fragment>
)
}
}
You can pass a reference to the this.deleteDebtor as props.
<Debt delete={this.deleteDebtor} debt={currentDebt} key={i} />;
const Debt = props => (
<tr>
<td>{props.debt.fullName}</td>
<td>{props.debt.damount}</td>
<td>
<button className="btn btn-danger btn-info " type="delete" onClick={() => props.delete(props.debt._id)}>DELETE</button>
</td>
</tr>
)
Note that this will re-render the component whenever the parent re-renders because a new function gets created on each render.
You can use React.memo to prevent that:
const Debt = React.memo(props => (
<tr>
<td>{props.debt.fullName}</td>
<td>{props.debt.damount}</td>
<td>
<button className="btn btn-danger btn-info " type="delete" onClick={() => props.delete(props.debt._id)}>DELETE</button>
</td>
</tr>
));
update
I think you have a scoping issue change the normal function inside map into an arrow function:
UserList() {
// console.log(this.state.users);
return this.state.users.map((currentDebt, i) => {
return <Debt delete={this.deleteDebtor} debt={currentDebt} key={i} />;
});
}
I have this code and want to add the people picker from https://social.technet.microsoft.com/wiki/contents/articles/37728.sharepoint-online-step-by-step-client-side-people-picker-control.aspx#Full_Code
import { Version } from '#microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '#microsoft/sp-webpart-base';
import { escape } from '#microsoft/sp-lodash-subset';
import styles from './FinanceSysAccWebPart.module.scss';
import * as strings from 'FinanceSysAccWebPartStrings';
import { SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
import { IListItem } from './app/interfaces/IListItem';
export interface IFinanceSysAccWebPartProps {
listName: string;
}
export interface ISpFxPureWebPartProps {
description: string;
}
export default class FinanceSysAccWebPart extends BaseClientSideWebPart<IFinanceSysAccWebPartProps>
{
private listItemEntityTypeName: string = undefined;
public render(): void {
this.domElement.innerHTML = `
<div class="${ styles.financeSysAcc }">
<div class="${ styles.container }">
<div class="${ styles.row }">
<div class="${ styles.column }">
<span class="${ styles.title }">Finance System Access Request Form</span>
<p class="${styles.description}">Name: ${escape(this.properties.listName)}</p>
<table>
<tr>
<td>First Name: </td>
<td><input id="txtFirstName" name="txtFirstName" type="text" /></td>
</tr>
<tr>
<td>Last Name: </td>
<td><input id="txtSurName" name="txtSurName" type="text" /></td>
</tr>
</table>
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
<div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<div class="status"></div>
<ul class="items"><ul>
</div>
</div>
</div>
</div>
</div>
</div>
`;
//let FirstName = (<HTMLInputElement> document.getElementById("txtFirstName")).value;
this.setButtonsEventHandlers();
}
What's the best way to do this? I can't see script tags in a webpart.
Use native JavaScript in SPFx solution would be more complex than classic page and no compile error/tip.
I would suggest you use #pnp/spfx-controls-react People Picker in your solution.
Demo thread
Delete function no longer works.
I deleted my information from Delete HTTP call and it works but when I used in angular2 part front end it does not work anymore.
error
DELETE http://localhost:3001/formations/undefined 0 ()
EXCEPTION: Response with status: 0 for URL: null
Subscriber.js:246 Uncaught Response {_body: ProgressEvent, status: 0, ok: false, statusText: "", headers: Headers, …}
zone.js:2019 DELETE http://localhost:3001/formations/undefined 0 ()
this is my formation.Service
deleteFormation(id){
return this.http.delete("http://localhost:3001/formations/"+id)
.map(res => res.json());
}
this is my home.ts
import { Component, OnInit } from '#angular/core';
import { FormationService } from '../../services/formation.service';
import { Formation } from '../../../app/formation';
import {Observable} from 'rxjs/Rx';
#Component({
selector: 'app-home1',
templateUrl: './home1.component.html',
styleUrls: ['./home1.component.css']
})
export class Home1Component implements OnInit {
formation: Observable<Formation[]>;
constructor(
public formationService:FormationService
) { };
ngOnInit() {
this.formation = this.formationService.getFormations();
// this.getFormations();
}
getFormations(){
this.formationService.getFormations()
.subscribe(formation=>{
this.formation = this.formation;
})
}
deleteFormation(id) {
this.formationService.deleteFormation(id)
.subscribe(()=>{
this.getFormations();
});
}
}
this my home.html
<app-navbar1></app-navbar1>
<table class="table table-bordered">
<thead>
<tr>
<td><b>Title</b></td>
<td><b>url</b></td>
<td><b>description</b></td>
<td width="275" align="center"><b>Action</b></td>
</tr>
</thead>
<tbody>
<tr *ngFor="let forms of formation | async " >
<td>{{forms.title}}</td>
<td>{{forms.url}}</td>
<td>{{forms.description}}</td>
<td width="275">
<a class="btn btn-info" routerLink="/show/{{formation._id}}">Detail</a>
<a class="btn btn-success" routerLink="/edit/{{formation._id}}" >Edit</a>
<a class="btn btn-danger" (click)="deleteFormation(formation._id)" >Delete</a>
</td>
</tr>
</tbody>
</table>
The problem with your code is that you are enumerating over a collection in *ngFor and instead of passing an instance of an object to deleteFormation method, you are passing collection.
Instead of deleteFormation(formation._id) you need to call deleteFormation(forms._id). _id does not exist on your formation array.
The same problem applies to your Detail and Edit links.
When I have done a function to see the details of a formation already added, nothing is displayed.
Error
GET http://localhost:3001/formations/undefined 0 ()
EXCEPTION: Response with status: 0 for URL: null
Subscriber.js:246 Uncaught Response {_body: ProgressEvent, status: 0, ok: false, statusText: "", headers: Headers, …}
This is my show.html
<div class="panel panel-default" >
<div class="panel-heading">formation detail Form : You can see the detail information of an foration in this page of the EMS Apps.</div>
<div class="panel-body">
<form class="form-horizontal" *ngIf=forms>
<div class="form-group">
<label for="emp_name" class="col-sm-2 control-label">formation's Full title : </label>
<div class="col-sm-9">
<p class="form-control">{{forms.title}}</p>
</div>
</div>
<div class="form-group">
<label for="position" class="col-sm-2 control-label">formation url : </label>
<div class="col-sm-9">
<p class="form-control">{{forms.url}}</p>
</div>
</div>
<div class="form-group">
<label for="department" class="col-sm-2 control-label">formation description : </label>
<div class="col-sm-9">
<p class="form-control">{{forms.description}}</p>
</div>
</div>
</form>
</div>
</div>
this is my show.ts
import { Component, OnInit } from '#angular/core';
import { FormationService } from '../../services/formation.service';
import { Formation } from '../../../app/formation';
import { ActivatedRoute, Params, Router } from '#angular/router';
#Component({
selector: 'app-show',
templateUrl: './show.component.html',
styleUrls: ['./show.component.css']
})
export class ShowComponent implements OnInit {
constructor(
public formationService:FormationService,
public route:ActivatedRoute,
public router:Router
) { }
ngOnInit() {
this.getFormation();
}
formation:Formation;
getFormation(){
var id = this.route.snapshot.params['id'];
this.formationService.getFormation(id)
.subscribe(formation=>{
this.formation = formation;
})
}
}
this is my home.html
<table class="table table-bordered">
<thead>
<tr>
<td><b>Title</b></td>
<td><b>url</b></td>
<td><b>description</b></td>
<td width="275" align="center"><b>Action</b></td>
</tr>
</thead>
<tbody>
<tr *ngFor="let forms of formation | async " >
<td>{{forms.title}}</td>
<td>{{forms.url}}</td>
<td>{{forms.description}}</td>
<td width="275">
<a class="btn btn-info" routerLink="/show/{{forms._id}}">Detail</a>
<a class="btn btn-success" routerLink="/edit/{{forms._id}}" >Edit</a>
<a class="btn btn-danger" (click)="deleteFormation(forms._id)" >Delete</a>
</td>
</tr>
</tbody>
</table>
this is my service file
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class FormationService {
constructor(private http:Http) { }
getFormations(){
return this.http.get("http://localhost:3001/formations")
.map(res => res.json());
}
addFormation(info){
return this.http.post("http://localhost:3001/formations",info)
.map(res => res.json());
}
getFormation(id){
return this.http.get("http://localhost:3001/formations/"+id)
.map(res => res.json());
}
deleteFormation(id){
return this.http.delete("http://localhost:3001/formations/"+id)
.map(res => res.json());
}
updateFormation(id, info){
return this.http.put("http://localhost:3001/formations/"+id,info)
.map(res => res.json());
}
}
I don't realy get you problem, but from what i see, you should
instead of
var id = this.route.snapshot.params['id'];
try to subscribe to the router using queryParams
this.formation = this.route.queryParams.pipe(map(params => {
this.id = params.id;
return this.formationService.getFormation(id)
})
in your html
<tbody *ngIf="formation | async as formation">
<tr *ngFor="let forms of formation">
</tr>
</tbody >
It seems that you send http request without id.
Just add a condition on the id:
getFormation(){
var id = this.route.snapshot.params['id'];
if(id){
this.formationService.getFormation(id)
.subscribe(formation=>{
this.formation = formation;
})
}
}
And it will be a good practice to add this check also in the service layer before sending request with 'id' as a a query param.