I have no idea why this isn't working and I'm stuck. Can anyone spot what is wrong with my code?
Im trying to show a Not found message when there are no tickets to show. I tried getting the result via tickets array lenght, but it always shows that the length is 0.
HTML
<ng-container *ngIf="tickets; else elseTemplate">
<div class="container">
<div class="row justify-content-md-center">
<div class="col-sm-4" *ngFor="let ticket of tickets">
<div class="card">
<h5 class="card-header"><span class="fa fa-ticket"></span> Pileti nr. {{ticket._id}}</h5>
</div>
</div>
</div>
</div>
</ng-container>
<ng-template #elseTemplate>
<div><h1>Ticket not found.</h1></div>
</ng-template>
TS
import { Component, OnInit } from '#angular/core';
import { TicketService } from '../../ticket.service';
import { ActivatedRoute } from '#angular/router';
import * as moment from 'moment';
import {Location} from '#angular/common';
#Component({
selector: 'app-reg-ticket-list',
templateUrl: './reg-ticket-list.component.html',
styleUrls: ['./reg-ticket-list.component.css']
})
export class RegTicketListComponent implements OnInit {
reg: string;
public tickets = [];
constructor(private ticketService: TicketService, private route: ActivatedRoute, private _location: Location) { }
ngOnInit() {
this.reg = this.route.snapshot.params.reg;
this.ticketService.getTicketsByReg(this.reg)
.subscribe(data => this.tickets = data);
}
dateFormat(date) {
moment.locale('et');
return moment(date).format("Do MMMM YYYY HH:mm:ss")
}
goBack() {
this._location.back();
}
}
When using *ngIf="tickets;, this will only check if tickets is falsey, and an empty array is not falsey (although null is).
Instead, you can use *ngIf="tickets && ticket.length; which will also check that there's the length is not 0
Related
I have a simple login form with email and password and when I try to send data to login.components.ts the form is empty
login.component.html:
<mat-spinner *ngIf="isLoading"></mat-spinner>
<form *ngIf="!isLoading" #loginForm="ngForm" (ngSubmit)="login(loginForm)">
<mat-form-field appearance="fill" class="login-full-width">
<mat-label>Enter your email</mat-label>
<input matInput [formControl]="email" type="email" name="email" placeholder="E-Mail" required>
<mat-error *ngIf="email.invalid">{{getErrorMessage()}}</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="login-full-width">
<mat-label>Enter your password</mat-label>
<input matInput [formControl]="password" name="password" [type]="hide ? 'password' : 'text'" required>
<button mat-icon-button matSuffix (click)="hide = !hide" [attr.aria-label]="'Hide password'" [attr.aria-pressed]="hide">
<mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
</button>
</mat-form-field>
<button mat-raised-button color="primary" type="submit">Login</button>
</form>
</mat-card>
login.component.ts
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Component, OnInit } from '#angular/core';
import { FormControl, NgForm, NgModel, Validators } from '#angular/forms';
import { response } from 'express';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private http: HttpClient) { }
ngOnInit(): void {
}
email = new FormControl('', [Validators.required, Validators.email]);
password = new FormControl('', [Validators.required]);
hide = true;
isLoading = false;
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
}
login(form: NgForm) {
console.log(form.value); <=========================== this is empty
this.http.post<{message: string}>('http://localhost:3000/login', form.value, this.httpOptions)
.subscribe((responseData) => {
console.log(responseData.message);
})
}
getErrorMessage() {
if (this.email.hasError('required')) {
return 'You must enter a value';
}
return this.email.hasError('email') ? 'Not a valid email' : '';
}
}
Console log is giving empty object
The "hello from express.js" is from the backend, which works fine (even tested with postman)
I think you are making the mistake of combining template-driven forms with reactive forms.
I will suggest using one approach to get the data out of it.
Example [formControl] is a reactive form item and you are submitting the form through the template-driven form. They don't work together.
I do not know the code to add the user, selected in a People Picker from the pnp.sp library.
I've tried the below code example (by using State) but this I understand is not saving the users selection.
private _getPeoplePickerItems() {
pnp.sp.web.siteUsers.get().then((data) =>{
this.setState({
DeptContact: data
});
});
}
And the people picker in the render:
<PeoplePicker
context={this.props.context}
titleText="People Picker"
personSelectionLimit={3}
groupName={''}
showtooltip={false}
isRequired={false}
disabled={false}
selectedItems={this._getPeoplePickerItems}
showHiddenInUI={false}
principalTypes={[PrincipalType.User]}
resolveDelay={1000}
/>
</div>
</div>
I expect a user to be able to enter a user into the people picker and resolve it and then submit it. This user is then added to a 'Person' column in a sharepoint list.
My test code for your reference(react framework).
import * as React from 'react';
import styles from './PnpReact.module.scss';
import { IPnpReactProps } from './IPnpReactProps';
import { escape } from '#microsoft/sp-lodash-subset';
import pnp from "#pnp/pnpjs";
import { PeoplePicker, PrincipalType } from "#pnp/spfx-controls-react/lib/PeoplePicker";
export interface IDefaultData{
PeoplePickerDefaultItems:string[];
}
export default class PnpReact extends React.Component<IPnpReactProps, IDefaultData> {
public constructor(props: IPnpReactProps,state: IDefaultData){
super(props);
this.state = {
PeoplePickerDefaultItems:[]
};
}
//get users from peoplepicker
private _getPeoplePickerItems(items: any[]) {
console.log(items);
}
public componentDidMount(){
this.GetDefaultUsers();
}
private GetDefaultUsers() {
pnp.sp.web.siteUsers.get().then((items: any[]) =>{
var defaultUsers:string[]=[];
//get last 2 users
for(var i=items.length-1;i>items.length-3;i--){
defaultUsers.push(items[i].Email);
}
this.setState({
PeoplePickerDefaultItems:defaultUsers
});
});
}
public render(): React.ReactElement<IPnpReactProps> {
return (
<div className={ styles.pnpReact }>
<div className={ styles.container }>
<div className={ styles.row }>
<PeoplePicker
context={this.props.context}
titleText="People Picker"
personSelectionLimit={3}
groupName={''}
showtooltip={false}
isRequired={false}
disabled={false}
selectedItems={this._getPeoplePickerItems}
defaultSelectedUsers={this.state.PeoplePickerDefaultItems}
showHiddenInUI={false}
principalTypes={[PrincipalType.User]}
resolveDelay={1000}
/>
<div className={ styles.column }>
<span className={ styles.title }>Welcome to SharePoint!</span>
<p className={ styles.subTitle }>Customize SharePoint experiences using Web Parts.</p>
<p className={ styles.description }>{escape(this.props.description)}</p>
<a href="https://aka.ms/spfx" className={ styles.button }>
<span className={ styles.label }>Learn more</span>
</a>
</div>
</div>
</div>
</div>
);
}
}
i implemented the jquery.datatables in my Angular 7, i installed all the node modules and did the necessary configuration, and included the necessary files in the angular.json file, and it works perfectly after the first run, but when i refresh the page or component, or move from one link to another and come back to the products page, the data loads from the api successfully but the datatable refuses to initialize properly...
and i'm lost on what to do.
Products Controller
import { Component, OnInit, ViewChild } from '#angular/core';
import { Router } from '#angular/router';
import { AccountService } from 'src/app/services/account.service';
import { ProductsService } from 'src/app/services/products.service';
import { Observable, Subject } from 'rxjs';
import { Product } from '../../interfaces/product';
import { DataTableDirective } from 'angular-datatables';
#Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
product$ : Observable<Product[]>;
products : Product[] = [] ;
//angular-datatables options..
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
#ViewChild(DataTableDirective, {static:true}) dtElement: DataTableDirective;
constructor(
private productService:ProductsService
){}
ngOnInit(): void {
this.productService.getAllProducts().subscribe(rst => {
this.products = rst; //assign the value of the observable to the array...
this.dtTrigger.next();
this.dtOptions = {
pageLength : 5,
autoWidth : true,
pagingType : 'full_numbers',
order : [[ 0, 'desc']]
}
});
}
}
the Product.component.html file
this is the code with the binding expressions
<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="table table-bordered row-border hover" style="width:100%">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>In Stock</th>
<th>Price( CAD) </th>
<th>Image</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of products" class="text-center">
<td>{{p.productId}}</td>
<td>{{p.name | uppercase}}</td>
<td>{{p.description}}</td>
<td>{{ (true == p.outOfStock)?'No':'Yes' }}</td>
<td>{{p.price | currency: 'CAD'}}</td>
<td> <img [src]="'/imgs/'+p.imageUrl" *ngIf="p.imageUrl" style="float:right" width="75" /> </td>
<td>
<div class="btn btn-group mt-2" role="group">
<button type="button" class="btn btn-success"><i class="fa fa-list"></i></button>
<button type="button" class="btn btn-primary"><i class="fa fa-pencil-square-o"></i></button>
<button type="button" class="btn btn-danger"><i class="fa fa-trash-o"></i></button>
</div>
</td>
</tr>
</tbody>
</table>
but on the first glance after logging in, everything works perfectly, but when i move go back to the page, only the data shows on the table shows after the ngFor loop, but the datatable refuses to initialize.. what do i do, and please whats my mistake..
You need to destroy datatable instance before triggering it again.
import { DataTableDirective } from 'angular-datatables';
dtElement: DataTableDirective;
isDtInitialized:boolean = false
this.products = rst;
if (this.isDtInitialized) {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
dtInstance.destroy();
this.dtTrigger.next();
});
} else {
this.isDtInitialized = true
this.dtTrigger.next();
}
Using this, for the first time it will go to the else block and trigger datatable directly. After that when you refresh, it will first destroy the datatable and then trigger.
Destroy the datatables instance before re-initializing. Make sure to also destroy the instance on destroy of the component using OnDestroy, like so:
public dt: DataTableDirective;
public isDtInit: boolean = false;
public dtInit(): void {
if (this.isDtInit) {
this.dt.dtInstance.then((dtInstance: DataTables.Api) => {
dtInstance.destroy();
this.dtTrigger.next();
});
} else this.isDtInit = true;
}
ngOnDestroy() {
this.dtInit();
}
Using this, for the first time it will go to the else block and trigger datatable directly. After that when you refresh, it will first destroy the datatable and then trigger.
See the code below,I use SSR in project, but some components just can render in browser-end since it use window or document object.So I do a switch, in server side: return null,and in browser-end return the real component. But I got a checksum error. What should I do?
render() {
if (!process.env.BROWSER) {
return null;
}
else {
const OwlCarousel = require('react-owl-carousel').default;
return <OwlCarousel
className="owl-theme"
loop margin={10} nav
>
<div className="item" style={{backgroundColor:'#3EA5E9'}}><h4>1</h4></div>
<div className="item"><h4>2</h4></div>
<div className="item"><h4>3</h4></div>
<div className="item"><h4>4</h4></div>
<div className="item"><h4>5</h4></div>
<div className="item"><h4>6</h4></div>
<div className="item"><h4>7</h4></div>
<div className="item"><h4>8</h4></div>
<div className="item"><h4>9</h4></div>
<div className="item"><h4>10</h4></div>
<div className="item"><h4>11</h4></div>
<div className="item"><h4>12</h4></div>
</OwlCarousel>;
}
}
example component
import { Component } from 'react'
export default class MyComponent extends Component {
state = { render: false }
componentDidMount() {
if (process.env.BROWSER) this.setState({ render: true })
}
render() {
return this.state.render && <ComponentToRender />
}
}
Got this error while trying to add PDF file into my website locally.
I have create one component called 'ViewPDF.jsx' and code for 'ViewPDF.jsx' is:
import React, { Component } from "react";
import { Page } from "react";
import { Document } from 'react-pdf/build/entry.webpack';
import PDF from 'react-pdf-js';
import { Resume } from '../Download/Resume.pdf';
class ViewPDF extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 0,
pages: 2
};
this.onDocumentComplete = this.onDocumentComplete.bind(this);
this.onPageComplete = this.onPageComplete.bind(this);
}
onDocumentComplete(pages) {
this.setState({ page: 1, pages });
}
onPageComplete(page) {
this.setState({ page });
}
render() {
return (
<div>
<PDF file="{Resume}"/>
</div>
);
}
}
export default ViewPDF;
And I have created page under src/screen/Contact.jsx
Code for 'Contact.jsx' is:
import React, { Component } from "react";
import Navbar from "../components/Navbar.jsx";
import Footer from "../components/Footer.jsx";
import Jumbotron from "../components/Jumbotron.jsx";
import { Document } from "react-pdf";
import ViewPDF from "../components/ViewPDF.jsx";
class Contact extends Component {
render() {
return (
<div>
<Navbar />
<Jumbotron title="welcome" subtitle="put something" />
<div className="container">
<h2>Contact Me</h2>
<p>
Email Address:
<a
href="mailto:abc4#gmail.com?Subject=Hello"
target="_top"
>
Click here for my Email Address
</a>
</p>
<p>
Click here for my resume!
resume
</p>
<ViewPDF />
</div>
<Footer />
</div>
);
}
}
export default Contact;
My PDF file is saved locally under src/Download/Resume.pdf.
I am newbie to React. When I open page in Chrome I got this error message:
Unhandled Rejection (UnknownErrorException): The API version "2.0.91" does not match the Worker version "1.10.97"
Thank you in advance!