Front-end Display Message "This email is already registered" PrimeNG & scss - node.js

I am not able to figure out how to inform a new registering user that email is already registered below the input element on entering email on my front-end in angular. Please assist. I am able to retrieve my async validation response as to whether the email is already registered or is available. I am using PrimeNG components and scss
In my Network Response, API response, I see {"email":"This eamil is already registered"} if the email is already registered and if the email is not registered, {"available":true}.
Below is the code for async validator in my unique-email.ts.
export class UniqueEmail implements AsyncValidator {
constructor(private authService: AuthService) {}
validate = (control: AbstractControl) => {
const { value } = control;
return this.authService.emailAvailable(value).pipe(
map((value) => {
if (value.available) {
return null;
}
}),
catchError((err) => {
if (err.error.email) {
return of({ EmailInUse: true });
} else {
return of({ noConnection: true });
}
})
);
};
}
Below is my code for AuthService.ts
interface EmailAvailableResponse {
available: boolean;
}
export class AuthService {
apiURLAuth = environment.apiUrl + 'users';
constructor(private http: HttpClient) {}
emailAvailable(email: string) {
return this.http.post<EmailAvailableResponse>(`${this.apiURLAuth}/emailexist`, {
email
});
}
}
My signup.component.ts
export class SignupComponent implements OnInit {
signupFormGroup: FormGroup;
isSubmitted = false;
authError = false;
constructor(
private matchPassword: MatchPassword,
private uniqueEmail: UniqueEmail,
private formBuilder: FormBuilder,
private authService: AuthService,
private localstorageService: LocalstorageService
) {}
private _initSignupForm() {
this.signupFormGroup = this.formBuilder.group(
{
email: ['', [Validators.required, Validators.email], [this.uniqueEmail.validate]]
}
)
}
get isignupForm() {
return this.signupFormGroup.controls;
}
}
<form [formGroup]="signupFormGroup">
<div class="col-12">
<div class="p-inputgroup">
<span class="p-inputgroup-addon"><i class="pi pi-id-card"></i></span>
<input type="text" formControlName="email" pInputText placeholder="Email" />
</div>
<small *ngIf="isignupForm.email.invalid && isSubmitted" class="p-error"
><span *ngIf="isignupForm.email.errors.required">Email is required</span>
<span *ngIf="isignupForm.email.errors.email">Email is Invalid</span>
<span *ngIf="isignupForm.email.errors.email.EmailInUse"
>Email is already registered to another user. Try another email account</span
>
</small>
</div>
</form>

There is an error for
isignupForm.email.errors.email.EmailInUse
Instead, use:
<span *ngIf="isignupForm.email.errors.EmailInUse">
Email is already registered to another user. Try another email account
</span>
Sample Demo on StackBlitz

Related

AngularFire Quickstart Not Returning Data From Firestore

Followed steps in AngularFire Quickstart
Add authentication as described in 5. Getting started with Firebase Authentication
When I set my Firestore rules to limit read and write access to authenticated users, I either get an error or I get nothing. For more details, see Issue #2838 filed in the GitHub repository.
My environment is:
Angular CLI: 12.0.1
Node: 14.17.0
Package Manager: npm 7.13.0
AngularFire: 6.1.5
Firebase: 8.6.1
Firebase Tools: 9.11.0
OS: Ubuntu 20.04.2 LTS (linux x64)
My Firestore rules are:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
allow write: if request.auth != null;
}
}
}
app.component.ts
import { Component, OnInit } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
import { AngularFireAuth } from '#angular/fire/auth';
import firebase from 'firebase/app';
import { Observable } from 'rxjs';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'Angular Fire Quickstart';
userDisplayName: string | null = null;
leagues$: Observable<any[]> = new Observable<any[]>();
constructor(
private firestore: AngularFirestore,
public auth: AngularFireAuth) {}
ngOnInit() {
// Recommended in Firebase documentation
this.auth.onAuthStateChanged((user) => {
if (user) {
this.userDisplayName = user.displayName;
this.leagues$ = this.firestore.collection('Leagues').valueChanges();
} else {
this.userDisplayName = null;
this.leagues$ = new Observable<any[]>();
}
});
}
login() {
this.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
}
logout() {
this.auth.signOut();
}
}
app.component.html
<div *ngIf="userDisplayName != null; else showLogin">
<p>Hello {{userDisplayName}}.
<button (click)="logout()">Logout</button>
</p>
<ul>
<li *ngFor="let league of leagues$ | async">
{{ league.name }} - {{ league.location }}
</li>
</ul>
</div>
<ng-template #showLogin>
<p>Please login.</p>
<button (click)="login()">Login</button>
</ng-template>
Resolved by subscribing to the Observable and changing my template to watch an array managed by the subscription. I now get data every time.
Here's the code with the changes:
app.component.ts
...
export class AppComponent implements OnInit {
title = 'Angular Fire Quickstart';
theUser: firebase.User | null = null;
leagueArray: Array<any> = []; // Eliminated the Observable in favor of an Array
constructor(
private firestore: AngularFirestore,
public auth: AngularFireAuth) {}
ngOnInit() {
this.auth.onAuthStateChanged((user) => {
if (user) {
this.theUser = user;
// Added the subscription and populated the array from there.
this.firestore.collection('Leagues').valueChanges().subscribe((data) => {
data.forEach((item) => {
this.leagueArray.push(item);
});
});
} else {
this.theUser = null;
this.leagueArray = [];
}
});
}
...
app.component.html
<div *ngIf="theUser != null">
<p>Hello {{theUser.displayName}}.
<button (click)="logout()">Logout</button>
</p>
<ul>
<!-- Watch the array instead of an Observable -->
<li *ngFor="let league of leagueArray">
{{ league.name }} - {{ league.location }}
</li>
</ul>
</div>

Laravel Echo listener is not listening

this is my first project with vue and nodejs so please let me know if I there is a missing information.
I'm trying to develop a group chat with Laravel, Vue js and Pusher.
Database Tables and Relations
I want to create a private Channel for each team which is available.
As soon as you click on the group chat, the existing messages get loaded and shown.
When you send a message, the message gets added to the messages table and is also sent successfully to pusher as you can see here:
Pusher message
The message is also added to the message list on the sender but not on the other team members.
Sender
Other team members
The new message is only shown on the other team members when they reload the page. That means that the echo listener doesn't seem to work. What can I do to fix it? What is wrong?
Here is my code:
ChatApp.vue (root component)
<template>
<div class="chat-container row">
<i class="far fa-comments fa-3x"></i>
<div id="chat-app" class="chat-app">
<div class="row mx-0 h-100 overflow-hidden">
<TeamList :teams="teamList" #selected="startConversationWith"/>
<Conversation :team="selectedTeam" :messages="messages" #new="saveNewMessage"/>
</div>
</div>
</div>
</template>
<script>
import MessageList from './MessageList';
import TeamList from './TeamList';
import Conversation from './Conversation';
import MessageTextBox from './MessageTextBox';
export default {
props: {
user: {
type: Object,
required: true
}
},
data() {
return {
messages: [],
teamList: [],
selectedTeam: null,
}
},
mounted() {
Echo.private('messages.1')
.listen('NewMessage', (e) => {
this.handleIncoming(e.message);
});
axios.get('/teams')
.then((response) => {
this.teamList = response.data;
});
},
methods: {
startConversationWith(team) {
axios.get('/conversation/' + team.id)
.then((response) => {
this.messages = response.data;
this.selectedTeam = team;
});
},
saveNewMessage(text) {
this.messages.push(text);
},
handleIncoming(message) {
this.saveNewMessage(message);
return;
}
},
components: {TeamList, MessageList, MessageTextBox, Conversation}
}
</script>
App/Events/NewMessage.php
<?php
namespace App\Events;
use App\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #param Message $message
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('messages.' . $this->message->team_id);
}
public function broadcastWith()
{
$this->message->load('team');
return ["message" => $this->message];
}
}
routes/channels.php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('messages.{id}', function ($team_id, $message) {
return true;
// return (int) $team->id === (int) $id;
});
Message model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
protected $guarded = [];
public function team()
{
return $this->belongsTo('App\Team');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
ContactsController
namespace App\Http\Controllers;
use App\Events\NewMessage;
use App\Message;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
class ContactsController extends Controller
{
public function getTeams() {
$teams = Auth::user()->teams;
return response()->json($teams);
}
public function getMessagesFor($id)
{
$messages = Message::where('team_id', $id)->get();
return response()->json($messages);
}
public function send(Request $request) {
$message = Message::create([
'team_id' => $request->team_id,
'user_id' => Auth::user()->id,
'message' => $request->text
]);
broadcast(new NewMessage($message));
return response()->json($message);
}
}
bootstrap.js
window._ = require('lodash');
/**
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
* for JavaScript based Bootstrap features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
try {
window.Popper = require('popper.js').default;
window.$ = window.jQuery = require('jquery');
require('bootstrap');
} catch (e) {}
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
encrypted is set to true for SSL config. Try setting it to false when configuring laravel echo in bootstrap.js
As you can see in the comments, setting encrypted to false in bootstrap.js solved the problem

MVC 5 Ajax.BeginForm Submit button calls current page instead of URL of Controller and Action specified

I'm trying to use Ajax.BeginForm, so I can pass the value of the checkbox to my Controller Action.
I was using #Ajax.ActionLink, but I can't get the value of the newly introduced checkbox, so I want to use Ajax.BeginForm going forward.
Since #Ajax.ActionLink is working in the View, I assume that Ajax is working properly, so I can rule that out.
Here are a couple of options I have tried. When I hover over the buttons, they both display the URL of my web page instead of the URL of the Controller and Action. When I click on the buttons, the page basically refreshes instead of calling the GetCode Action in the PublicOffers Controller.
Any help is much appreciated! Thanks!
Option 1
<div>
#using (Ajax.BeginForm("GetCode", "PublicOffers", null, new AjaxOptions()
{
UpdateTargetId = "detailsDiv",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
OnBegin = "onStart",
OnComplete = "onComplete",
OnSuccess = "myCallback"
}))
{
//bool checkedOption = false;
//#Html.CheckBoxFor(x => checkedOption, new { Name = "OptIn" })
#Html.CheckBoxFor(model => model.OptIn);
#Html.HiddenFor(model => model.Id);
<input type="submit" value="Get Code" class="button btn-primary" />
}
</div>
Option 2
<div>
#using (Ajax.BeginForm(new AjaxOptions()
{ HttpMethod = "GET",
Url = "PublicOffers/GetCode",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "detailsDiv",
OnBegin = "onStart",
OnComplete = "onComplete",
OnSuccess = "myCallback"
}))
{
//bool checkedOption = false;
//#Html.CheckBoxFor(x => checkedOption, new { Name = "OptIn" })
#Html.CheckBoxFor(model => model.OptIn)
//#Html.HiddenFor(model => model.Id, new { Name = "OfferId" })
#Html.HiddenFor(model => model.Id);
#Html.AntiForgeryToken()
<input type="submit" value="Submit" />
}
</div>
This is not exactly an answer but it might help.
First be sure you have this, I use NuGet to install it,
Microsoft.jQuery.Unobtrusive.Ajax
Then be sure it gets emitted to the page, either though bundle scripts or a script link in the cshtml
First a simple model...
namespace AjaxTest.Models
{
public class AjaxTestModel
{
public bool OptIn { get; set; }
}
}
Next some cshtml...
#model AjaxTest.Models.AjaxTestModel
#{ ViewBag.Title = "AjaxTest1";}
<h2>AjaxTest1</h2>
#using (Ajax.BeginForm("AjaxTest1", "Home", null,
new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "OnSuccess(xhr)",
OnFailure = "OnFailure(xhr, status)"
},
new { id = "myform" }))
{
#Html.CheckBoxFor(model => model.OptIn);
<span id="lbl_message"></span>
<br />
<button id="btn_submit" type="submit" class="">Submit</button>
}
#section scripts{
<script>
$(document).ready(function () {
console.log("ready to rock and roll....");
});
function OnBegin() {
console.log("OnBegin");
}
function OnSuccess(xhr) {
console.log("OnComplete");
$("#lbl_message").text("Ok:" + xhr.responseJSON.param2);
}
function OnFailure(xhr, status) {
console.log("OnFailure");
$("#lbl_message").text("Error:" + xhr.responseJSON.param2);
}
</script>
}
The magic is in the controller, notice that I am returning a Json object, not a view.
public class HomeController : Controller
{
public ActionResult AjaxTest1()
{
AjaxTestModel model = new AjaxTestModel();
return View();
}
[HttpPost]
public ActionResult AjaxTest1(AjaxTestModel model)
{
if (model.OptIn)
{
dynamic errorMessage = new { param1 = "param1", param2 = "You opted in." };
HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
return Json(errorMessage, JsonRequestBehavior.AllowGet);
}
else
{
dynamic errorMessage = new { param1 = "param1", param2 = "You opted out." };
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
return Json(errorMessage, JsonRequestBehavior.AllowGet);
}
}
}
Note, The HttpContext.Response.StatusCode will control which Ajax callback is activate, return HttpStatusCode.Ok and the OnSuccess gets called, return the HttpStatusCode.NotFound, or most any other error code, and the OnFailure will get called.
I got it to work by adding a beginning Ajax.BeginForm method. It's almost like the first instance invokes the second Ajax.BeginForm method. Since there is no button or anything else in the first method, nothing displays on the page.
NOTE: I changed my Get to a Post so the [ValidateAntiForgeryToken] attribute would work on the Controller Action. I read that it would not work with a Get.
<div>
#using (Ajax.BeginForm("GetCode", "PublicOffers", new { offerId = Model.Id }, new AjaxOptions()
{
//Nothing here, but for some reason without this code the Ajax.BeginForm below won't work
}))
{
//Nothing here, but for some reason without this code the Ajax.BeginForm below won't work
}
</div>
<div>
#using (Ajax.BeginForm("GetCode", "PublicOffers", new { offerId = Model.Id },
new AjaxOptions { OnBegin = "onStart", UpdateTargetId = "detailsDiv",
InsertionMode = InsertionMode.Replace, HttpMethod = "Post",
OnComplete = "onComplete",
OnSuccess = "myCallback"},
new { #style = "display:inline-block" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<div class="form-group">
#Html.CheckBoxFor(model => model.OptIn, new { Name = "optIn"})
</div>
</div>
<input type="submit" class="button btn-primary" value="Get Code" id="get-code button" />
}
</div>
Here is my Controller Action.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> GetCode(Guid offerId, bool optIn = false)
{
//Code here
return PartialView("_OfferCode");
}

Rendering modal on click (user action) react redux

I am rendering modal using react and redux.
I've seen thousand of examples of how to create a modal, but none on how to fire it inside another component.
I took the same approach to render modals on redux
on this question
My store is this:
export const store=createStore(
rootReducer,
compose(
applyMiddleware(thunk)
))
And the main component:
class Main extends React.Component {
render () {
return(
<BrowserRouter>
<Provider store={store} >
<App/>
</Provider>
</BrowserRouter>
)
}}
The app component is where I am guessing I should render the modal
class App extends React.Component {
render () {
return(
<div className="main-app">
<Home />
<Modal />
</div>
)
}}
But how can I update the state of this Modal component from within the components inside <Home >
My modal component looks like this:
import LoginModal from './LoginModal';
const MODAL_COMPONENTS = {
'LOGIN': LoginModal
}
class ModalRoot extends React.Component {
render() {
const SpecificModal = MODAL_COMPONENTS[this.props.modal.modalType];
if(!this.props.modal.showModal) return <SpecificModal />
return null
}
}
let mapStateToProps=state=>{
return {
modal: state.modal
}
}
export default connect(mapStateToProps)(ModalRoot);
Which will be the best approach to change the state three (store) of my redux app to change the state of the modal?
Thanks
Suppose you want to trigger the modal by clicking a button in Home button. You can pass in dispatch function to Home using mapDispatchToProps and dispatch action that changes the state of modal from there.
actions.js
function changeModal(payload) {
return {
type: 'CHANGE_MODAL',
payload,
}
}
reducer
// below defines what's in store.modal
function modalReducer(state = {}, action) {
switch(action.type) {
case: 'CHANGE_MODAL':
return {
...state,
...action.payload
}
// ... rest of your code
}
}
Home component
class Home extends Component {
//... rest of logic
changeModal = (modal) => {
const currentModal = {
showModal: true,
modalType: modal,
}
this.props.changeModal({ modal: currentModal });
}
render() {
// im using 2 buttons to trigger different modals,
return <div>
<button onClick={() => this.changeModal('HOME')}>trigger home modal</button>
<button onClick={() => this.changeModal('OTHER')}>trigger other modal</button>
</div>
}
}
const mapDispatchToProps = (dispatch) => ({
changeModal: (payload) => dispatch(changeModal(payload))
});
// insert mapDispatchToProps as a second argument to connect
// home component may or may not have mapStateToProps
export default connect(mapStateToProps, mapDispatchToProps)(Home);
So when you press the button, the state.modal will change and it will show the modal depending on the new state.

Page-change event not working in ng2-bootstrap

I am trying to implement the pagination in my angular2 app with the ng2-bootrap. am following http://valor-software.github.io/ng2-bootstrap/#pagination
my app.html
<div>
<div class="col-lg-12 text-right">
<pagination [totalItems]="bigTotalItems" (page-changed)="pageChanged($event)" [(ngModel)]="bigCurrentPage" [maxSize]="maxSize"
class="pagination-sm" [boundaryLinks]="true"></pagination>
</div>
</div>
my component
import { Component, View, Inject} from 'angular2/core';
import { CORE_DIRECTIVES } from 'angular2/common';
import { PAGINATION_COMPONENTS } from 'ng2-bootstrap/ng2-bootstrap';
// webpack html imports
#View({
templateUrl: '/scripts/src/components/demo/demo.html',
directives: [PAGINATION_COMPONENTS, CORE_DIRECTIVES]
})
#Component({
selector: 'tabs-demo',
})
export class DemoComponent {
private totalItems: number = 64;
private currentPage: number = 4;
private maxSize: number = 5;
private bigTotalItems: number = 175;
private bigCurrentPage: number = 1;
private setPage(pageNo: number): void {
this.currentPage = pageNo;
};
private pageChanged(event: any): void {
console.log('Page changed to: ' + event.page);
console.log('Number items per page: ' + event.itemsPerPage);
};
}
but when i change the pagination page its not triggering the pagechanged event.
Please correct me to work it properly.
The Output is called pageChanged, not page-changed

Resources