Angular and RxJs: handling expiration of verification code
I have a simple component to verify user's email. It consists of "Send Email" (that sends email with code) button, text input to enter sent code and "Verify" button that sends code to back for verification. Berification code expires in 5 minutes. And if I resend email new code expires in 5 minutes after resend.
I'm using OnPush
change detection strategy so everything is handled with async pipes. The observable wrapping "Send Email" request is passed to template as async pipe. I want to have an other observable that will emit something (e.g. true
) when 5 minutes passed. Yes, I can use delay
operator in the way like the following
expired$ = sendObservable$.pipe(delay(5 * 60 * 1000), mapTo(true))
But. What if user decide to resend email? How can I restart these 5 minutes from the beginging?
And yes, I understand that all of that is somewhat strange. Maybe there's totaly different way to handle expiration of code using observables and async pipes?
1 answer
-
answered 2021-02-23 00:02
Petr Averyanov
debounceTime delays values emitted by the source Observable, but drops previous pending delayed emissions if a new value arrives on the source Observable. This operator keeps track of the most recent value from the source Observable, and emits that only when dueTime enough time has passed without any other value appearing on the source Observable. If a new value appears before dueTime silence occurs, the previous value will be dropped and will not be emitted on the output
So, simply:
expired$ = sendObservable$.pipe(debounceTime(5 * 60 * 1000))
See also questions close to this topic
-
How to show a confirmation when user leaves the window - JS
I want to call a button click event when user tries to leave the page. That button click have a confirmation message. Using below java script , I can call the button click event when user leaves the page and the confirmation message is popup correctly. But I want the user to navigate out of the page as usual when clicks 'CANCEL' on the confirmation box. Or after clicking 'OK' once. But, now when clicks on 'OK' or 'CANCEL', and user tries to leave the mouse out of page,the popup is coming again. How can I control this?
$(document).mouseleave(function () { document.getElementById("<%=btn_save.ClientID %>").click();}); function Confirm2() { var confirm_value = document.createElement("INPUT"); confirm_value.type = "hidden"; confirm_value.name = "confirm_value"; if (confirm("Do you want to save the details? ")) { confirm_value.value = "OK"; } else { confirm_value.value = "CANCEL"; } document.forms[0].appendChild(confirm_value); } <asp:ImageButton ID="btn_save" autopostback="false" runat="server" ImageUrl="~/images/BtnSave.png" Width="145px" Height="48px" CausesValidation="false" OnClientClick="Confirm2()" OnClick="onclick_Save" />
-
Execute function A every 2 seconds, execute function B every millisecond for 1 second, then pause for 1 second, and then repeat in JS
Like the title of the question of say, I want functions A and B to happen in those time intervals in JavaScript. Function A is done easily with setInterval(A, 2000), but I'm not sure how I would make B happen. I can think of a method where I set a variable k and increment it every millisecond, and then either reset it to 0 when it reaches 1000 or take a modulo, but I wanted to know if there was any special syntax to perform these timing events.
-
hide navigation menu when click on blank area
So, I have this code, and I'm trying to understand how it works
This is perfect working navigation menu.. when click on "cut button" menu hide perfect without any problem..
Let's say, I wanna make it auto hide when click on blank right side area,
how to get this javascript?
Begginer here, so thanks to everyone! :)
! function(e) { var t = {}; function n(o) { if (t[o]) return t[o].exports; var r = t[o] = { i: o, l: !1, exports: {} }; return e[o].call(r.exports, r, r.exports, n), r.l = !0, r.exports } n.m = e, n.c = t, n.d = function(e, t, o) { n.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: o }) }, n.r = function(e) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 }) }, n.t = function(e, t) { if (1 & t && (e = n(e)), 8 & t) return e; if (4 & t && "object" == typeof e && e && e.__esModule) return e; var o = Object.create(null); if (n.r(o), Object.defineProperty(o, "default", { enumerable: !0, value: e }), 2 & t && "string" != typeof e) for (var r in e) n.d(o, r, function(t) { return e[t] }.bind(null, r)); return o }, n.n = function(e) { var t = e && e.__esModule ? function() { return e.default } : function() { return e }; return n.d(t, "a", t), t }, n.o = function(e, t) { return Object.prototype.hasOwnProperty.call(e, t) }, n.p = "", n(n.s = 0) }([function(e, t, n) { "use strict"; n.r(t); var o; n(1); window.addEventListener("resize", (function() { document.body.classList.add("resize-animation-stopper"), clearTimeout(o), o = setTimeout((function() { document.body.classList.remove("resize-animation-stopper") }), 400) })); var r = document.querySelector(".nav-toggle"), i = document.querySelector(".menu-toggle"); r.addEventListener("click", (function(e) { this.classList.toggle("open"), i.classList.toggle("active"), e.stopPropagation() })), document.querySelector(".dropdown a").addEventListener("click", (function(e) { this.nextElementSibling.classList.toggle("show"), this.parentNode.classList.toggle("active"), e.stopPropagation() })), document.querySelector(".second-level a").addEventListener("click", (function(e) { this.nextElementSibling.classList.toggle("show"), this.parentNode.classList.toggle("active"), e.stopPropagation() })) }, function(e, t, n) {}]);
* { margin: 0; padding: 0; } html { -webkit-box-sizing: border-box; box-sizing: border-box; } *, :after, :before { -webkit-box-sizing: inherit; box-sizing: inherit; } body { width: 100%; background-color: #eee; color: #222; } header { padding: 0; margin: 0; } .nav__container, header { width: 100%; background-color: #fafafa; } .nav__container { -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; flex-direction: column; -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; -webkit-box-align: stretch; -ms-flex-align: stretch; align-items: stretch; padding: 0 1px; } .nav__mobile .nav__btn { display: block; margin: 4px 6px 4px 0; } .nav__mobile { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; -webkit-box-align: center; -ms-flex-align: center; align-items: center; background: #0a499014; } .nav__logo { font-size: 15px; font-weight: 700; color: #555; z-index: 99; width: 76%; background: #e6ebf1; } .nav__menu { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; flex-direction: column; overflow: hidden; border-top: 1px solid #fff; } .showing { max-height: 37rem; -webkit-transition: all 0.5s; transition: all 0.5s; } .nav__menu li { list-style: none; position: relative; white-space: nowrap; padding: 1rem 0 0; } .nav__menu li a { display: block; font-size: 18px; padding-left: 26px; color: #fff; text-decoration: none; } .nav__menu .dropdown ul a { margin-left: 10px; } .nav__menu .dropdown .second-level ul { margin-left: 15px; } .nav-toggle { display: block; background-color: #1abc9b; width: 52px; height: 51px; cursor: pointer; padding: 11px 6px; border-radius: 3px; } .nav-toggle span { position: relative; display: block; height: 6px; border-radius: 17px; width: 100%; margin-top: 0; background-color: #fff; -webkit-transition: all 0.25s; transition: all 0.25s; } .nav-toggle span.mrg { margin-top: 5px; } .nav-toggle.open span:first-child { -webkit-transform: rotate(45deg) translate(7.2px, 7.2px); transform: rotate(45deg) translate(7.2px, 7.2px); } .nav-toggle.open span:nth-child(2) { width: 0; opacity: 0; } .nav-toggle.open span:last-child { -webkit-transform: rotate(-45deg) translate(7.2px, -7.2px); transform: rotate(-45deg) translate(7.2px, -7.2px); } .nav__menu .dropdown ul { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; flex-direction: column; position: static; padding: 0; max-height: 0; overflow: hidden; -webkit-transition: all 0.4s; transition: all 0.4s; } .nav__menu .dropdown ul.show { max-height: 20rem; -webkit-transition: all 0.4s; transition: all 0.4s; } .nav__menu .dropdown li a { display: block; font-size: 0.875rem; text-transform: capitalize; color: #fff; } .nav__menu li a:hover { color: #0062a3; } .nav__menu .dropdown ul a:before { content: "\0272A"; padding-right: 4px; font-size: 15px; } .nav__menu .dropdown > a:after { content: "\276F"; font-weight: 900; font-size: 0.875rem; padding-left: 5px; color: #1abc9b; } .nav__menu .active.dropdown > a:after { content: "\02C5"; } .nav__menu .dropdown .dropdown > a:after { content: "\276F"; font-weight: 900; font-size: 0.875rem; padding-left: 5px; color: #1abc9b; } .nav__menu .dropdown .active.dropdown > a:after { content: "\02C5"; } .menu-toggle { max-height: 0; overflow: scroll; position: fixed; width: 80%; z-index: 15; height: 100%; top: 0; left: 0; background-color: #883442; transform: translateX(-100%); } nav.menu-toggle.active { transform: translateX(0); } .menu-toggle, .menu-toggle.active { transition: transform 0.2s ease-in-out; } .menu-toggle.active { max-height: 100vh; padding: 50px 0 0 0; } .resize-animation-stopper * { transition: none !important; -webkit-transition: none !important; animation: none !important; -webkit-animation: none !important; }
<header> <div class="nav__container"> <div class="nav__mobile"> <div class="nav__logo"> <a href="#"><img src="https://www.examsbook.com/img/home/examsbook_logo.png" alt="Exam"></a> </div> <div class="nav__btn"> <a aria-label="Mobile menu" class="nav-toggle fade"><span></span><span class="mrg"></span><span class="mrg"></span></a> </div> </div> <nav class="menu-toggle"> <ul class="nav__menu"> <li><a href="">Menu item 1</a></li> <li><a href="">Menu item 2 </a></li> <li><a href="">Menu item 3 </a></li> <li class="dropdown"><a href="#">Dropdown</a> <ul> <li><a href="">Dropdown item 1</a></li> <li><a href="">Dropdown item 2</a></li> <li><a href="">Dropdown item 3</a></li> <li class="dropdown second-level"><a href="#">2nd level dropdown</a> <ul> <li><a href="">Dropdown item 1</a></li> <li><a href="">Dropdown item 2</a></li> <li><a href="">Dropdown item 3</a></li> </ul> </li> <li><a href="">Dropdown item 3</a></li> <li><a href="">Dropdown item 4</a></li> </ul> </li> <li><a href="">Menu item</a></li> <li><a href="">Menu item</a></li> <li><a href="">Menu item</a></li> </ul> </nav> </div> </header>
-
How to recognise zoom in/out functionality of mouse on overall desktop?
In angular we have zoom in out of window. I want zoom in out which do on screen level to big small text. Example: when font-size is 12 then we zoom in screen then it shows us as big but at coding level its size 12 only but view wise its around 80px then how to realize that?
-
I create a template driven form to add products using angular 11 and json-server
but when I adding new product to this form I got this error, my validations are ok, but this status 500 (internal server error) It always comming from my browser console.
my error is,
TypeError: Cannot read property 'id' of undefined at Function.createId (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\lib\server\mixins.js:58:39) at Function.insert (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash-id\src\index.js:47:49) at C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:4430:28 at arrayReduce (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:697:21) at baseWrapperValue (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:4429:14) at LodashWrapper.wrapperValue (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\lodash\lodash.js:9114:14) at create (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\lib\server\router\plural.js:239:48) at Layer.handle [as handle_request] (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\layer.js:95:5) at next (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:137:13) at next (C:\Users\ACER\AppData\Roaming\npm\node_modules\json-server\node_modules\express\lib\router\route.js:131:14)
my service file is,
import { Injectable } from '@angular/core'; import {HttpClient, HttpHeaders} from "@angular/common/http"; @Injectable({ providedIn: 'root' }) export class ProductService { constructor( private httpClient :HttpClient) { } getProducts(){ return this.httpClient.get('http://localhost:3000/products'); } addProduct(data:any){ // const httpHeader =new HttpHeaders(); // httpHeader.append('content-type' ,'application/json') return this.httpClient.post('http://localhost:3000/products',data); } }
my component.ts file is,
import { Component, OnInit } from '@angular/core'; import {ProductService} from "../../product.service"; import {NgForm} from "@angular/forms"; @Component({ selector: 'app-addproduct', templateUrl: './addproduct.component.html', styleUrls: ['./addproduct.component.css'] }) export class AddproductComponent implements OnInit { constructor(private productService :ProductService) { } msg =false; ngOnInit(): void { } addNew(addproduct:NgForm){ const product ={ productID :addproduct.value.pid, productName:addproduct.value.pname, price :addproduct.value.price } this.productService.addProduct(product).subscribe(result=>{ this.msg =true; },error => { console.log(error) }) } }
my component.html file is,
<div class="container mt-4"> <div class="row"> <div class="col-md-2"> </div> <div class="col-md-8"> <!-- Template Driven Form--> <form #addproduct="ngForm" class="form-group" (ngSubmit)="addNew(addproduct)" > <div class="alert alert-success" *ngIf="msg"> Product Added Successfully </div> <br><br> <div class="form-group"> <label for="exampleInputId">ProductID :</label> <input type="number" class="form-control" id="exampleInputId" name="pid" placeholder=" product Id" required #name1='ngModel' ngModel> <div class="alert alert-danger" *ngIf="!name1.valid"> <span *ngIf="name1?.errors?.required"> This name is required</span> </div> </div> <div class="form-group"> <label for="exampleInputPName">Product Name :</label> <input type="text" class="form-control" id="exampleInputPName" name="pname" placeholder=" product name" required #name2='ngModel' minlength="3" ngModel> <div class="alert alert-danger" *ngIf="!name2.valid"> <span *ngIf="name2?.errors?.required"> This name is required</span> <span *ngIf="name2?.errors?.minlength">You must enter atleast 3 characters</span> </div> </div> <div class="form-group"> <label for="exampleInputPrice"> Price :</label> <input type="text" class="form-control" id="exampleInputPrice" name="price" placeholder=" price of this product" required #name3='ngModel' minlength="3" ngModel> <div class="alert alert-danger" *ngIf="!name3.valid"> <span *ngIf="name3?.errors?.required"> This name is required</span> <span *ngIf="name3?.errors?.minlength">You must enter atleast 3 characters</span> </div> </div> <button type="submit" class="btn btn-success" [disabled]="!addproduct.valid" >Add Product</button> </form> </div> <div class="col-md-2"> </div> </div> </div>
my db.json file is according to json-server,
{ "products":[ {"productID":1 , "productName": "pen" , "price" : 40}, {"productID":2 , "productName": "pencil" , "price" : 20}, {"productID":3 , "productName": "bottle" , "price" : 150} ] }
plz help me to fix this error,
-
Cdeitor 4 "unselectable" null - Angular 8
My project angular 8. When I add ckeditor 4 to the project, I get the following error.
zone-evergreen.js:172 Uncaught TypeError: Cannot read property 'unselectable' of null at e (ckeditor.js:349) at a.<anonymous> (ckeditor.js:346) at a.d (ckeditor.js:10) at a.<anonymous> (ckeditor.js:11) at a.CKEDITOR.editor.CKEDITOR.editor.fire (ckeditor.js:13) at a.fireOnce (ckeditor.js:12) at a.CKEDITOR.editor.CKEDITOR.editor.fireOnce (ckeditor.js:13) at Object.<anonymous> (ckeditor.js:273) at g (ckeditor.js:253) at Object.load (ckeditor.js:253)
app.module.ts
import { CKEditorModule } from 'ckeditor4-angular'; @NgModule({ imports: [ CKEditorModule ]
app.componenet.html
<nb-card-body> <ckeditor [data]="editorData"></ckeditor> </nb-card-body>
-
rxjs - Filter stream events with boolean observable stream value
this.mainObservable$.pipe( iWantThisOperator(() => !this.theLatestObservableBooleanValue$) ).subscribe(() => { console.log('Stream Event') })
"This not the actual code, I just want to describe it"
I want the operator that can handle to filter my mainObservable events depending on the latest observable stream boolean value
So I want all the mainObservable events only if theLatestObservableBooleanValue$ is false
-
Error: No overload matches this call. Problem with angular project
[GitHub post]https://github.com/laststonedjs/Oak/issues/1#issue-823991737I worked on Angular Project and I have some error in my " product.component.ts " Pls help if u can.
-
Angular Reactive Form inputs are empty after using *ngIf directive
I am new to angular and I am trying to implement a reactive form. I will only put a few lines of code so it will be more easy to follow. I have a parent component:
page: number; ngOnInit() { this.addProjectForm = this.formBuilder.group({ projectId: ['', Validators.required], projectName: [''], startDate: [''], user: [this.user.email], country: ['', Validators.required], projectType: [this.projectTypeValue, Validators.required], }); this.page = 1; } clickNext() { this.page = this.page + 1; } clickBack() { this.page = this.page - 1; }
In the parent html I have two child components:
<nb-card> <nb-card-body id="first-page" *ngIf="page === 1"> <div class="form-group"> <label for="projectType" class="label">Bid / Delivery Product</label> <nb-select class="select-column" (selectedChange)="saveProjectType();ngOnInit()" id="projectType" formControlName="projectType"> <nb-option value="bid">Bid</nb-option> <nb-option value="deliveryProduct">Delivery Product</nb-option> </nb-select> </div> <delivery-template *ngIf="this.addProjectForm.value.projectType == 'deliveryProduct'" [deliveryProjectForm]="addProjectForm"></delivery-template> <bid-template *ngIf="this.addProjectForm.value.projectType == 'bid'" [bidProjectForm]="addProjectForm"></bid-template> </nb-card-body> <nb-card-body id="second-page" *ngIf="page === 2"> <!-- some data --> </nb-card-body> <nb-card-body id="third-page" *ngIf="page === 3"> <!-- some data --> </nb-card-body> <nb-card-footer> <button nbButton [disabled]="page === 3 || !addProjectForm.valid" class="btn float-left ml-2" type="button" (click)="clickNext()">Next </button> <button nbButton [disabled]="page === 1" type="button" (click)="clickBack()">Go Back </button> <button nbButton [disabled]="page !== 3" type="submit" (click)="onSubmit()">Save </button> </nb-card-footer> </nb-card>
On the child components (bid-template and delivery template) I am passing the addProjectForm:
// Only showing delivery-template because bid-template is almost the same @Input() deliveryProjectForm: FormGroup; ngOnInit() { if (this.deliveryProjectForm.contains('projectid')) { this.deliveryProjectForm.setControl('projectid', new FormControl('', Validators.required)); } else { this.deliveryProjectForm.addControl('projectid', new FormControl('', Validators.required)); } // same for the rest of the properties } // getters get projectId() { return this.deliveryProjectForm.get('projectid'); } // same for the rest of the properties
And on delivery-template html:
<form [formGroup]="deliveryProjectForm"> <div class="col"> <div class="form-group"> <label for="project_id" class="label">Project ID</label> <input nbInput id="project_id" type="text" class="form-control" placeholder="Project ID" formControlName="projectid"> <div *ngIf="projectId.invalid && (projectId.dirty || projectId.touched)" class="text-danger"> <small *ngIf="projectId.errors.required"> Project ID is required! </small> </div> </div> </div> <!-- Same for the rest of properties --> </form>
With the form valid and all the fields completed clicking Next and then clicking Back() to the input fields every input field is empty even tough in the debugger addProjectForm has the previous entered values. But the problem is that deliveryProjectForm has empty values after going back. If I am using [hidden] instead of *ngIf the values are restored. Why is this happening?
Thank you.