Uncaught TypeError: Cannot read properties of null (reading 'imageLink')
The above error occurred in the <ProductMoreDetails> component:
This Products page Display all the products in the database. When I click on any product card it will redirects to the more details page of that product. First time it loads without any issue and when I refresh the page or backward the page it will disappear all the content in the page.
ProductMoreDetails.js
import Navbar from "../components/Navbar";
import { useProductsContext } from "../hooks/useProductsContext";
import { useParams } from "react-router-dom";
import { useEffect } from "react";
//setproducts
const ProductMoreDetails = () => {
const {products,dispatch} = useProductsContext();
const {id} = useParams();
useEffect(() => {
const fetchProducts = async () => {
const response = await fetch(`/api/products/${id}`)
const json = await response.json()
if (response.ok) {
dispatch({type: 'SET_PRODUCTS', payload: json})
}
}
fetchProducts()
},[dispatch,id])
return (
<div className="moredetails">
<Navbar/>
<br /><br />
<div className="details">
<img className="productImage" src={products.imageLink} alt="productImage" />
<div className="details-section"></div>
<div className="row section1">
<div className="col-lg-8">
</div>
<div className="col-lg-2">
<button className="btn btn-primary addnew">Add to Cart</button>
</div>
</div>
<div className="row section1">
<div className="col-lg-8">
<h1>{products.productName}</h1>
</div>
<div className="col-lg-2">
<h1>Rs. {products.price}</h1>
</div>
</div>
<div className="section1">
<hr />
<h1>Product Details</h1>
<br />
<div className="row">
<div className="col-lg-6">
<div className="row">
<div className="col-lg-6">
<h6>Category</h6>
</div>
<div className="col-lg-6">
<p>{products.category}</p>
</div>
</div>
</div>
<div className="col-lg-6">
<div className="row">
<div className="col-lg-6">
<h6>Brand</h6>
</div>
<div className="col-lg-6">
<p>{products.brand}</p>
</div>
</div>
</div>
</div>
<br />
<div className="row">
<div className="col-lg-6">
<div className="row">
<div className="col-lg-6">
<h6>Model</h6>
</div>
<div className="col-lg-6">
<p>{products.model}</p>
</div>
</div>
</div>
<div className="col-lg-6">
<div className="row">
<div className="col-lg-6">
<h6>Year</h6>
</div>
<div className="col-lg-6">
<p>{products.year}</p>
</div>
</div>
</div>
</div>
<br />
<div className="row">
<div className="col-lg-6">
<div className="row">
<div className="col-lg-6">
<h6>Features</h6>
</div>
<div className="col-lg-6">
<p>{products.features}</p>
</div>
</div>
</div>
</div>
<hr />
<div className="section2">
<h1>Product Description</h1>
</div>
<p>
{products.description}
</p>
</div>
</div>
</div>
)
}
export default ProductMoreDetails;
ProductContext.js
import { createContext } from "react";
import { useReducer } from "react";
export const ProductsContext = createContext();
export const productsReducer = (state, action) => {
switch (action.type) {
// set products
case "SET_PRODUCTS":
return {
...state,
products: action.payload,
}
//set a single product
case "SET_PRODUCT":
return {
...state,
products: action.payload,
}
case 'CREATE_PRODUCT':
return {
products: [action.payload, ...state.products]
}
case 'DELETE_PRODUCT':
return {
products: state.products.filter((product) => product._id !== action.payload._id)
}
case 'UPDATE_PRODUCT':
return {
products: state.products.map((product) => product._id === action.payload._id ? action.payload : product)
}
default:
return state;
}
}
export const ProductsContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(productsReducer, {
products: null
})
return (
<ProductsContext.Provider value={{...state, dispatch}}>
{ children }
</ProductsContext.Provider>
)
}
Related
I have three components called blog cards that are rendered with an image and text. Depending on how long the text is the cards are of different heights. I want to render them, then get the tallest one, and sort of re-render them, so they are all the same height.
Here is the Page
import * as React from 'react'
import { SocialIconRow } from '#/components/social-icons'
import BlogPostCard from '#/components/BlogCard'
import Image from 'next/image'
import { useState, useEffect } from 'react'
import { FixedSizeList } from 'react-window'
function BlogPostCardsList({ cards }) {
const tallestCardHeight = useMemo(() => {
return Math.max(...cards.map(card => card.height))
}, [cards])
return (
<FixedSizeList
itemCount={cards.length}
itemSize={tallestCardHeight}
width={'100%'}
height={'100%'}
>
{({ index, style }) => <BlogPostCard style={style} {...cards[index]} />}
</FixedSizeList>
)
}
export default function MyComponent(props) {
const [cardHeight, setCardHeight] = useState(null);
const [maxHeight, setMaxHeight] = useState(0);
useEffect(() => {
const calculateHeight = () => {
const cards = document.querySelectorAll('.blog-post-card');
let heights = [];
cards.forEach(card => {
heights.push(card.clientHeight);
});
setMaxHeight(Math.max(...heights));
}
calculateHeight();
setCardHeight(maxHeight);
}, []);
return (
<>
<div className="container mx-auto flex flex-col">
<div className="container mx-auto flex">
<div className="w-1/2 pr-4">
<div className="text-4xl font-bold">Mike Borman</div>
<div className="text-lg mt-2">Writer, Content Creator and Developer on Cardano</div>
</div>
<div className="w-1/2 flex flex-col justify-center">
<div className="max-h-48 max-w-48 mx-auto my-auto">
<Image
src="/images/myfaceppgray.png"
alt="Picture of the author"
className="max-h-48 max-w-48"
width="150"
height="150"
unoptimized={true}
/>
</div>
<div className="mt-4">
<SocialIconRow className="social-icon-row" />
</div>
</div>
</div>
<div className="mt-8">
<div className="text-3xl font-bold">Featured Blogs</div>
<div className="grid grid-cols-3 gap-4 h-full mt-4 align-items-stretch">
<div style={{height: cardHeight}}>
<BlogPostCard
title="The Hydra Protocol Family — Scaling and Network Optimization for the Cardano Blockchain"
slug="the-hydra-protocol-family-scaling-and-network-optimization-for-the-cardano-blockchain"
imageslug="/images/hydra.png"
className="blog-post-card"
/>
</div>
<div style={{height: cardHeight}}>
<BlogPostCard
title="Ouroboros, A deep dive for non PhDs"
slug="ouroboros-a-deep-dive-for-non-phd"
imageslug="/images/ourobouros.png"
className="blog-post-card"
/>
</div>
<div className="h-full row-auto" style={{height: cardHeight}}>
<BlogPostCard
title="Ouroboros, A deep dive for non PhDs"
slug="ouroboros-a-deep-dive-for-non-phd"
imageslug="/images/ourobouros.png"
className="blog-post-card"
/>
</div>
</div>
</div>
</div>
</>
)
}
Here is the Card component:
import React from 'react'
import Link from 'next/link'
import Image from 'next/image'
function BlogPostCard(props) {
const { title, slug, imageslug } = props
return (
<Link href={`/blog/${slug}`}>
<a className="block flex flex-col justify-between rounded-md border-2 border-teal-400 transition-all duration-300 ease-in-out hover:scale-105 hover:shadow-lg">
<img className="rounded-t-md h-48 w-full object-cover" src={imageslug} alt="blog post cover" />
<span className="text-white text-2xl p-4">{title}</span>
</a>
</Link>
)
}
export default BlogPostCard
I tried dynamically rendering them then setting them, btw I have no idea really what Im doing there.
You actually have all but one class already to do this entirely in CSS. Just add h-full to your a tag inside the BlogPostCard component's Link. Then you can get rid of all of the JS. Optionally, you could also remove the justify-between or change it to justify-stretch so that the titles of the blog posts are directly beneath of the post cover images.
In the demo below, you can see the result by clicking run code snippet. Also, if you're upgrading to NextJS 13, it's worth noting that you no longer need (and in fact can't have) an a tag as a child of Link. I'd suggest using article as I've done below, which will be more semantically correct anyway.
function BlogPage({posts}) {
return (
<main className="container mx-auto my-8">
<div className="flex gap-4">
<div className="w-1/2">
<h1 className="text-4xl font-bold">Mike Borman</h1>
<h2 className="text-lg mt-2">
Writer, Content Creator and Developer on Cardano
</h2>
</div>
<div className="w-1/2 flex flex-col justify-center items-center">
<span className="w-[150px] h-[150px] bg-neutral-300 rounded-full grid place-content-center">author img here</span>
<span>social row here</span>
</div>
</div>
<section className="mt-8">
<header>
<h2 className="text-3xl font-bold">Featured Blogs</h2>
</header>
<div className="grid grid-cols-3 gap-4 h-full mt-4 align-items-stretch">
{posts.map((post) => (
<BlogPostCard key={post.id} {...post} />
))}
</div>
</section>
</main>
)
}
function BlogPostCard({ slug, imageslug, title,}) {
return (
<Link href={`/blog/${slug}`}>
<article className="flex flex-col justify-stretch h-full rounded-md border-2 border-teal-400 bg-neutral-600 transition-all duration-300 ease-in-out hover:scale-105 hover:shadow-lg">
<img
className="rounded-t-md h-48 w-full object-cover"
src={imageslug}
alt="blog post cover"
/>
<span className="text-white text-2xl p-4">{title}</span>
</article>
</Link>
)
}
/* Stubbing out next/link here since I can't run NextJS in code snippets */
function Link({ href, children, className }) {
return (
<a href={href} className={className}>
{children}
</a>
)
}
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<BlogPage posts={[
{
id: 1,
title: 'The Hydra Protocol Family — Scaling and Network Optimization for the Cardano Blockchain',
slug: 'the-hydra-protocol-family-scaling-and-network-optimization-for-the-cardano-blockchain',
imageslug: 'https://d3lkc3n5th01x7.cloudfront.net/wp-content/uploads/2019/05/15233606/700-X-394.png',
},
{
id: 2,
title: 'Ouroboros, A deep dive for non PhDs',
slug: 'ouroboros-a-deep-dive-for-non-phd',
imageslug: 'https://www.almaviva.it/dam/jcr:6212e8ef-1ed6-40e2-a75f-b6fa7c814662/Blockchain_1280x720.jpg',
},
{
id: 3,
title: 'How Blockchain Is Used',
slug: 'how-blockchain-is-used',
imageslug: 'https://imageio.forbes.com/specials-images/imageserve/5f2a32ee3b52675a453e2881/Fascinating-Examples-Of-How-Blockchain-Is-Used-In-Insurance--Banking-And-Travel/960x0.jpg?format=jpg&width=960',
},
]} />
);
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
<div id="root"></div>
I have a problem to loading data with API call with axios, I have an infinit loop when the method loadTasks() is called.
I want to load todo list, and load associated tasks inside. Maybe I'm using the wrong way.
Here my template with Todo liste v-for loop and inside an another v-loop lo display Task list associated, loaded with loadTasks(list.id).
<template >
<div class="todo-list-container">
<div class="list flex flex-col max-w-sm mx-auto">
<hr class="text-gray1 mb-4">
<div v-for="list in allTodoList" :value="list.id" :key="list.id" class="mb-4 px-4 py-2 bg-gray-dark rounded-xl ">
<div class="flex items-center gap-4 mb-4">
<div class="date text-sm text text-left text-gray1">{{ list.order }}</div>
<div class="title font-bold">{{ list.title }}</div>
<div class="ml-auto font-bold text-right">
<button v-if="list.id" #click="this.$store.dispatch('removeTodoList', list.id)">Supprimer</button>
</div>
</div>
<div class="task-container">
{{loadTasks(list.id)}}
<div v-if="loading">loading...</div>
<div v-if="tasks" class="list weekList flex flex-col p-6 max-w-sm mx-auto bg-gray rounded-xl shadow-lg">
<div class="flex flex-row gap-4">
Liste des taches <button #click="displayForm(list.id)" href="#" class="px-2 rounded bg-blue text-white text-sm uppercase right">+</button>
<hr class="text-gray1 mb-4">
</div>
<div v-for="task in tasks" :value="task.id" :key="task.id" class=" mb-4 flex items-center gap-4 flex-row">
<div class="date text-sm text text-left text-gray1">{{ task.position }}</div>
<div class="">
<div class="title font-bold">{{ task.title }}</div>
<div class="date text-sm text text-left text-gray1">Terminé <input type="checkbox" name="finish" id="" :checked="task.finish" ></div>
</div>
<div class="ml-auto font-bold text-right">
<button v-if="task.id" #click="this.$store.dispatch('removeTask', task.id)">Supprimer</button>
</div>
</div>
</div>
</div>
</div>
{{this.$store.state.error}}
<div :class="[ showForm === true ? '' : 'hidden' ] + ' addNewForm'">
<add-task-form :listId="getListId" :showForm="showForm" ></add-task-form>
</div>
</div>
</div>
</template>
Script:
<script>
import addTaskForm from './addTaskForm.vue';
import axios from 'axios';
axios.defaults.baseURL = 'http://localhost:3000';
export default {
name: 'todoList',
props: ['allTodoList'],
components: {
addTaskForm,
},
data() {
return {
loading: false,
visibleForm: false,
listId: 0,
tasks: [],
};
},
methods: {
displayForm(listId) {
this.listId = listId;
this.visibleForm = !this.visibleForm;
},
async loadTasks(listId) {
try {
if(!listId) { return; }
const tasksList = await axios.get(`/list/${listId}/tasks`);
if (!tasksList.data.tasks || !tasksList.data.tasks.length) {
return;
}
else {
this.tasks = tasksList.data.tasks
}
} catch (error) {
this.$store.dispatch('setError', error);
}
},
cancelForm() {
this.visibleForm = false;
},
},
computed: {
showForm() {
return this.visibleForm;
},
getListId() {
return this.listId;
},
},
}
</script>
i have looked up every relating posts for 8hours but still cant solve it
{comments.map((c) => {
console.log(c)
return(
<div className="col-lg-12" key={c._id}>
<div className="testi-item">
<div className="testi-comment">
<p>
<i className="fa fa-quote-left" />
{c.message}
<i className="fa fa-quote-right" />
</p>
<ul className="stars list-unstyled">
<li>
<i className="fa fa-star" />
</li>
<li>
<i className="fa fa-star" />
</li>
<li>
<i className="fa fa-star" />
</li>
<li>
<i className="fa fa-star-half-alt" />
</li>
<li>
<i className="fa fa-star" />
</li>
</ul>
</div>
<div className="client-info">
<h5>{c.companyName}</h5>
<p>{c.ip}</p>
</div>
</div>
</div>
states
const [comments, setComments] = useState([]);
const getComments = async function () {
try {
const response = await axios.get("/comment");
console.log(response);
setComments(response.data.comments);
} catch (error) {
console.error(error);
}
};
smaple object
{ companyName: "asd" ip: "112.214.38.68" message: "asd" _id: "6162fb4c06b4541fa2420f5c" }
enter image description here
Uncaught Error: Objects are not valid as a React child (found: object with keys {_id, companyName, message, ip}). If you meant to render a collection of children, use an array instead.
please help
complete code
import React, { useState } from "react";
import OwlCarousel from "react-owl-carousel";
import "owl.carousel/dist/assets/owl.carousel.css";
import "owl.carousel/dist/assets/owl.theme.default.css";
import ScreenHeading from "../../utilities/ScreenHeading/ScreenHeading";
import ScrollService from "../../utilities/ScrollService";
import Animations from "../../utilities/Animations";
import "./Testimonial.css";
import shape from "../../../src/img/Testimonial/shape-bg.png";
import Comment from "../CommentComponent/Comment";
import axios from "axios";
import lady from "../../../src/img/Testimonial/lady.png";
import mike from "../../../src/img/Testimonial/mike.png";
import man from "../../../src/img/Testimonial/man.png";
export default function Testimonial(props) {
const [comments, setComments] = useState([]);
const getComments = async function () {
try {
const response = await axios.get("/comment");
console.log(response);
setComments(response.data.comments);
} catch (error) {
console.error(error);
}
};
let fadeInScreenHandler = (screen) => {
if (screen.fadeInScreen !== props.id) return;
Animations.animations.fadeInScreen(props.id);
getComments();
};
const fadeInSubscription =
ScrollService.currentScreenFadeIn.subscribe(fadeInScreenHandler);
const options = {
loop: true,
margin: 0,
nav: true,
animateIn: "bounceInRight",
animateOut: "bounceOutRight",
dots: true,
autoplay: true,
smartSpeed: 1000,
responsive: {
0: {
items: 1,
},
768: {
items: 1,
},
1000: {
items: 3,
},
},
};
return (
<div>
<ScreenHeading title={"Valuable Comments"} subHeading={"방명록 리스트"} />
<section className="testimonial-section fade-in" id={props.id || ""}>
<div className="container">
<div className="row">
<OwlCarousel
className="owl-carousel"
id="testimonial-carousel"
{...options}
>
{comments}
{!comments ? (
<div>non</div>
) : (
<div>
{comments.map((c) => {
console.log(c)
return (
<div className="col-lg-12" key={c._id}>
<div className="testi-item">
<div className="testi-comment">
<p>
<i className="fa fa-quote-left" />
{c.message}
<i className="fa fa-quote-right" />
</p>
<ul className="stars list-unstyled">
<li>
<i className="fa fa-star" />
</li>
<li>
<i className="fa fa-star" />
</li>
<li>
<i className="fa fa-star" />
</li>
<li>
<i className="fa fa-star-half-alt" />
</li>
<li>
<i className="fa fa-star" />
</li>
</ul>
</div>
<div className="client-info">
<h5>{c.companyName}</h5>
<p>{c.ip}</p>
</div>
</div>
</div>
);
})}
</div>
)}
</OwlCarousel>
</div>
</div>
</section>
<div className="footer-image">
<img src={shape} alt="not responding" />
</div>
</div>
);
}
You’ve embedded a bare {comments} in your render function right before the ternary; comments is an object and can’t be dropped into the DOM raw, just like the error message is telling you.
Remove that line and it should be fine.
The issue is here:
{comments}
You should remove this line.
If you woule like to see the comments you should do:
{JSON.stringify(comments)}
How can i block access to the pages once login has been completed in VueJS.
Also how can i display my server validation errors using bootstrap invalid-feedback class?
Please comment if you have any questions regarding my code or want me to clarify anything more in-depth.
<template>
<div>
<div class="h-100 bg-plum-plate bg-animation">
<div class="d-flex h-100 justify-content-center align-items-center">
<b-col md="8" class="mx-auto app-login-box">
<div class="app-logo-inverse mx-auto mb-3"/>
<div class="modal-dialog w-100 mx-auto">
<div class="modal-content">
<div class="modal-body">
<div class="h5 modal-title text-center">
<h4 class="mt-2">
<div>Welcome back,</div>
<span>Please sign in to your account below.</span>
</h4>
</div>
<b-form-group id="Admin Email" label-for="Admin Email">
<b-form-input
id="Admin Email"
type="email"
required
placeholder="Enter email..."
v-model="email">
</b-form-input>
<div class="invalid-feedback">
{{errorMsg}}
</div>
</b-form-group>
<b-form-group
id="Admin Password"
label-for="Admin Password"
>
<b-form-input
id="Admin password"
type="password"
required
placeholder="Enter password..."
v-model="password"
></b-form-input>
<div class="invalid-feedback">
{{errorMsg}}
</div>
</b-form-group>
<b-form-checkbox name="check" id="exampleCheck">
Keep me logged in
</b-form-checkbox>
<div class="divider"/></div>
<div class="modal-footer clearfix">
<div class="float-left">
<a
href="javascript:void(0);"
class="btn-lg btn btn-link"
>
Recover Password</a>
</div>
<div class="float-right">
<b-button variant="primary" size="lg" #click="signin">
Login to Dashboard
</b-button>
</div>
</div>
</div>
</div>
<div class="text-center text-white opacity-8 mt-3"></div>
</div>
</div>
</b-col>
</div>
</div>
</div>
</template>
<script>
import Authentication from '../../services/authenticationService.js'
import {store} from '../../store.js'
export default {
name: 'HelloWorld',
data () {
return {
email: '',
password: '',
store: store.state.login,
errorMsg: '',
stored: store
}
},
methods: {
async signin () {
try{
const login = await Authentication.login({
email: this.email,
password: this.password
})
var secured = login.data.token.split(' ')[1]
sessionStorage.setItem('jwt', login.data.token)
if (sessionStorage.getItem('jwt') != null || sessionStorage.getItem('jwt') == login.data.token)
{
this.stored.isLoggedIn()
this.$router.push('/admin')
} else {
this.$router.push('/admin/login')
}
}
catch(err){
if(err.response){
this.errorMsg = err.response.data.message
}else if(err.request){
this.errorMsg = err.request
}else{
this.errorMsg = err.message
}
this.errorMsg = err;
}
}
}
}
</script>
You can either check in the created hook, or check in the beforeRouteEnter guard.
You could also check this out for a third option which uses beforeEach
Login.vue - Using the created hook
<script>
export default {
created() {
if(/* If logged in */){
this.$router.push('/admin')
}
}
}
</script>
Using beforeRouteEnter
<script>
import { store } from '../../store'
export default {
beforeRouteEnter(to, from, next) {
if(/* Check store if logged in */){
next('/admin')
} else {
next()
}
}
}
</script>
Hi I need to update login name in a header after a user logs in.
this is my code:
app.componet.html
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
app.component.ts
import { Component,OnDestroy } from '#angular/core';
import { MyservicesService } from './myservices.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
constructor(private myservices: MyservicesService) {
}
}
Header.component.html
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<img class="img-responsive" src="assets/images/logo.png" alt="logo">
</div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav navbar-right">
<li><a routerLink="home" routerLinkActive="active">Home</a></li>
<li><a routerLink="shop">Shop</a></li>
<li>About us</li>
<li>Contact</li>
<li *ngIf="displayuser" class="dropdown">
<a class="dropdown-toggle displaycurrentuser" data-toggle="dropdown" href="#">{{currentusername}}
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a (click)="logOut()">Log out</a></li>
</ul>
</li>
<li *ngIf="!displayuser"><button style="margin-top: -10px;" class="btn btn-primary"> Login / Register</button></li>
<li><a routerLink="cartlist"><span><i class="fa fa-shopping-cart" aria-hidden="true"></i> {{noofitemsincart}} </span></a></li>
</ul>
</div>
</div>
</nav>
Header.component.ts
import { Component, OnInit,Input } from '#angular/core';
import { AuthenticationService } from '../authentication.service';
import { MyservicesService } from '../myservices.service';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
displayuser:boolean = false;
currentusername;
noofitemsincart;
user:any;
constructor(private authenticationService: AuthenticationService,private myservices: MyservicesService) {
}
ngOnInit() {
this.user = this.authenticationService.getCurrentUserData();
if(this.user!=null){
//this.user=JSON.parse(this.user);
if(this.user.UserNameorEmail!=null){
this.displayuser=true;
console.log("displayuser "+this.displayuser);
this.currentusername=this.user.UserNameorEmail;
}
}
}
logOut() {
this.user= this.authenticationService.logout();
this.displayuser=false;
}
}
Loginorregistercomponent.html
<section class="news_area newsblock">
<div class="container">
<div class="row">
<div class="section-title">
<h2>my <span>account</span></h2>
</div>
</div>
<!--endrow-->
<div class="row">
<div class="col-md-6 col-sm-6 col-xs-12 spaceblock">
<div class="login">
<h3 class="titlel">Login</h3>
</div>
<form name="form" (ngSubmit)="loginform.form.valid && login()" #loginform="ngForm" novalidate>
<div class="loginpart">
<div class="form-group froma" [ngClass]="{'has-error': loginform.submitted && !username.valid}">
<label for="email">Username or email address <span class="required"> *</span></label>
<input type="email" class="form-control" id="email" placeholder="" name="username" name="username" [(ngModel)]="model.username"
#username="ngModel" required>
<div *ngIf="loginform.submitted && !username.valid" class="help-block">Username is required</div>
</div>
<div class="form-group" [ngClass]="{ 'has-error': loginform.submitted && !password.valid }">
<label for="pwd">Password<span class="required"> *</span></label>
<input type="password" class="form-control" id="pwd" placeholder="" name="password" [(ngModel)]="model.password" #password="ngModel"
required>
<div *ngIf="loginform.submitted && !password.valid" class="help-block">Password is required</div>
</div>
<div class="checkbox">
<label><input type="checkbox" name="remember"> Remember me</label>
</div>
<button [disabled]="lloading" type="submit" class="btn btn-primary">Login</button>
<img *ngIf="lloading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=="
/>
<div class="lostpass">Lost your password?</div>
<div *ngIf="lerror" class="danger">{{lerror}}</div>
</div>
</form>
</div>
<div class="col-md-6 col-sm-6 col-xs-12 spaceblock">
<div class="login">
<h3 class="titlel">Register</h3>
</div>
<form name="form" (ngSubmit)="registerform.form.valid && register()" #registerform="ngForm" novalidate>
<div class="loginpart">
<div class="form-group froma" [ngClass]="{ 'has-error': registerform.submitted && !newusername.valid }">
<label for="email">Email address <span class="required"> *</span></label>
<input type="email" class="form-control" id="email" placeholder="" name="newusername" [(ngModel)]="registermodel.newusername"
#newusername="ngModel" required>
<div *ngIf="registerform.submitted && !newusername.valid" class="help-block">Username is required</div>
</div>
<div class="form-group" [ngClass]="{ 'has-error': registerform.submitted && !newpassword.valid }">
<label for="pwd">Password<span class="required"> *</span></label>
<input type="password" class="form-control" id="pwd" placeholder="" name="newpassword" [(ngModel)]="registermodel.newpassword"
#newpassword="ngModel" required>
<div *ngIf="registerform.submitted && !newpassword.valid" class="help-block">Password is required</div>
</div>
<button type="submit" [disabled]="rloading" class="btn btn-primary">Register</button>
<img *ngIf="rloading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=="
/>
<div *ngIf="rerror" class="danger">{{rerror}}</div>
</div>
</form>
</div>
</div>
<!--endimgSection-->
</div>
</section>
Loginorregistercomponent.ts
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { AuthenticationService } from '../authentication.service';
#Component({
selector: 'app-loginorregister',
templateUrl: './loginorregister.component.html',
styleUrls: ['./loginorregister.component.css']
})
export class LoginorregisterComponent implements OnInit {
model: any = {};
registermodel: any = {};
lloading = false;
rloading = false;
returnUrl: string;
lerror;
rerror;
constructor( private route: ActivatedRoute,
private router: Router,
private authenticationService: AuthenticationService) { }
ngOnInit() {
this.authenticationService.logout();
// get return url from route parameters or default to '/'
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
}
login() {
this.lloading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
console.log(data);
if(!data.hasOwnProperty('Code')){
this.router.navigate([this.returnUrl]);
}else{
this.lerror=data.Message;
console.log(this.lerror);
this.lloading = false;
}
},
error => {
//this.alertService.error(error);
this.lerror=error;
console.log(error);
this.lloading = false;
});
}
register() {
this.rloading = true;
this.authenticationService.create(this.registermodel.newusername, this.registermodel.newpassword)
.subscribe(
data => {
data=JSON.parse(data);
if(!data.hasOwnProperty("Code")){
this.router.navigate([this.returnUrl]);
console.log("in data "+data);
}
else{
console.log("out data "+data.Message);
this.rerror=data.Message;
this.rloading = false;
}
},
error => {
// this.alertService.error(error);
this.rerror=error;
this.rloading = false;
});
}
}
authenticationService.ts
import { Injectable } from '#angular/core';
import { Http, Headers, RequestOptions, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map'
#Injectable()
export class AuthenticationService {
user:any;
headers = new Headers({ 'Content-Type': 'application/json' });
options = new RequestOptions({ headers: this.headers });
constructor(private http: Http) { }
login(username: string, password: string) {
return this.http.post('http://www.myweb.com/User/Login', JSON.stringify({UserNameorEmail: username,Password: password}),this.options)
.map((response: Response) => {
let user = response.json();
console.log("in service "+user);
if (user) {
localStorage.setItem('currentUser', JSON.stringify(user));
console.log("user.token "+user);
}
return user;
});
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
}
create(username: string, password: string) {
return this.http.post('http://www.myweb.com/User/Add', JSON.stringify({UserNameorEmail: username, Password: password }),this.options)
.map((response: Response) => {
let user = response.json();
if (user) {
localStorage.setItem('currentUser', JSON.stringify(user));
}
return user;
});
}
getCurrentUserData(){
this.user= localStorage.getItem("currentUser");
this.user=JSON.parse(this.user);
if(this.user!=null){
if(this.user.UserNameorEmail!=null){
return this.user;
}else{
return this.user=null;
}
}else{
return this.user=null;
}
}
}
I typically have a state.service.ts in my projects in which I store application state (current user etc.)
In this, I create the following:
// BehaviorSubject to store UserName
private currentUserNameStore = new BehaviorSubject<string>("");
// Make UserName store Observable
public currentUserName$ = this.currentUserNameStore.asObservable();
// Setter to update UserName
setCurrentUserName(userName: string) {
this.currentUserNameStore.next(userName);
}
Then in the header component where you need to display the current User, you subscribe to the Observable from your state service:
stateSvc.currentUserName$
.subscribe(
userName => {
userName = userName;
});
And you can display this in the header like this:
{{userName}}
Then in your login component, once you've got a logged in user, you set the value using the Setter in the service:
this.stateSvc.setCurrentUserName(this.userName);
As the Title on the header component is subscribed, it will pickup the changes and update the display on the component.
You have to check authenticity of user before loading <app-header> </app-header>
i.e.
<div *ngIf="authorised">
<app-header></app-header>
</div>
where authorised is a member of app.component.ts.
i.e. You have to make sure if displayuser or currentusername is available before rendering <app-header></app-header>.
Please mark if you find it helpful.