Angular validator to check availability - javascript

I'm creating a Reactive Form in angular to register some devices. In this form I ask for a serial number, and I want to check if this serial number is already registered in my database.
When I type in the input form it activates the function serialNumAvailability to display or not a message. This function calls a service function called checkSerialNumAvailability which send a get request to my back-end. I made some console.log and used Postman to test the get request, and it seems to work fine on the back-end side. But at the moment I type one character in the input field, I go back to my home page, and I can't understand why...
Here is my HTML template verification:
<input formControlName="serialNum" type="text" class="form-control" placeholder="Ex: SL07101-BL" name="serialNum" required>
<div *ngIf="f.submitted " class="help-block mt-2 text-danger" i18n> Serial Number is required</div>
<div *ngIf="serialNum?.value.errors.serialNumAvailability" i18n> Serial Number already registered</div>
Then my component function serialNumAvailability :
serialNumAvailability(control: FormControl) {
return Observable.timer(500).switchMap(() => {
return this.portalService.checkAvailabilitySerialNum(control.value)
.map(res => {
if (res && res.length == 1 && res[0].serialNum) {
console.log("ON RENVOIE TRUE");
return { serialNumAvailability: true};
}
console.log("ON RENVOIE NULL");
return null;
});
});}
My service function :
checkAvailabilitySerialNum(term: string): Observable<Portal[]> {
let portals: Portal[];
if (!term.trim()) {// if search is empty
return Observable.of([]);
}
return this.http.get<Portal[]>(this.serverURL + `portal/?serialNum=${term}`)
.map(Portals => Portals.filter(portals => portals.serialNum === term)
);
}
And finally the Node side :
router.get('/',
function (req, res) {
console.log("ON RENTRE BIEN DANS LA FONCTION : " + req.query.serialNum);
return models.portals.findAll({
attributes: ['serialNum'],
where: {
serialNum: req.query.serialNum
}
}).then((serialNums) => {
if (serialNums) {
serialNums = serialNums.map((serialNum) => {
serialNum = serialNum.toJSON();
console.log(serialNum);
return serialNum;
})
}
console.log("ON FAIT RES.SEND DE "+serialNums);
res.send(serialNums);
})
})
I don't know why I'm redirected, if someone has encountered this problem, thanks for support :)

Finally the problem was solved. The redirection was due to a token interceptor which handled my request. As it was not authorized to GET information, I simply added an exception to this interceptor for my URL.
This looks like this :
if (req.headers.has(this.config.InterceptorSkipHeader)) {
let headers = req.headers.delete(this.config.InterceptorSkipHeader);
return next.handle(req.clone({ headers }));
}
if(this.authenticationService.isLoggedIn()){
this.authenticationService.updateExpiration();
}
else if (this.router.routerState.snapshot.url != "/register-portal"){
this.router.navigate(['/login'], { queryParams: { returnUrl: ''} });
}
Thanks to those who answered :)

Related

Check if data in URL is valid before navigate to page

I would like to configure my Angular component, so that the page only loads if the ID in the URL is valid. The point here is, that I want to protect the page from users manually entering a random URL, and accessing any page.
I have a component with lists.
If I click on the "Show Details", Angular navigates to the details page. I would like to only open this page, if the entered URL contains a valid ID. To achieve this, I call a service to gather all IDs into an array of strings. And then examine if the entered ID is a member of that array.
What I have tried:
list.component.ts:
ngOnInit() {
this.fetchLists();
}
fetchLists() {
from(this.listService.getGroups())
.pipe(
takeUntil(this.destroy$)
)
.subscribe({
next: (listUI: ListUI[]) => {
this.listData = listUI;
},
error: (error) => {
this.logger.debug(error.message);
this.certError = true;
}
});
}
details.component.ts:
ngOnInit() {
this.fetchListsAndIDs();
if (this.validIDsList.includes(listID)) {
this.router.navigateByUrl(`/groups/lists/${listID}/details`);
}
else {this.router.navigateByUrl(`/groups/lists`);}
}
fetchListsAndIDs() {
from(this.listService.getGroups())
.pipe(
takeUntil(this.destroy$)
)
.subscribe({
next: (listUI: ListUI[]) => {
const listData = listUI;
this.validIDsList = listData.map((lists) => lists.id);
},
error: (error) => {
this.logger.debug(error.message);
this.certError = true;
}
});
}
app.routing.module.ts
{
path: 'groups/lists/${listID}/details',
component: DetailsComponent
}
The page "groups/lists/99999999999/details" opens, with zero data, and "this.validIDsList" is undefined. Can someone please help me how to fix this?
You almost have the right code, but you missed the part that, this.fetchListsAndIDs() is executing an asynchronous observable, so your if..else block is executing before even the API call completes.
I would suggest, you include the if...else check inside the next() handler. I have reversed the conditions to check for NOT first, since you are already in details.components.ts which represents ``/groups/lists/${listID}/details) route, you should only redirect the user back to lists if id is not valid, else the component should continue with its work.
I added code to grab the listId from URL. It is missing in the code you posted in the question.
ngOnInit() {
this.listID = this.route.snapshot.paramMap.get('listID');
this.fetchListsAndIDs();
}
fetchListsAndIDs() {
from(this.listService.getGroups())
.pipe(
takeUntil(this.destroy$)
)
.subscribe({
next: (listUI: ListUI[]) => {
const listData = listUI;
this.validIDsList = listData.map((lists) => lists.id);
this.handleNavigation();
},
error: (error) => {
this.logger.debug(error.message);
this.certError = true;
}
});
}
handleNavigation() {
if (!this.validIDsList.includes(this.listID)) {
this.router.navigateByUrl(`/groups/lists`);
} else {
// call the function to continue with details component
}
}

Stripe not being called

I am trying to use Vue.js for my front end to call Stripe and create a token which then is sent to my backend. I have tested everything using plain HTML/JS and it all works fine, my issue comes in trying to use Vue.js I think my issue might be in how I am binding the stripe public key. Below is my code, and I have zero output to speak of, I get just redriected to the same page but wth ? at the end of the URL. Nothing else, console shows nothing and no error message or anything send to my back end.
template code
There is more but not related
<div class="col-md-8">
<card class='stripe-card col-md-8'
:class='{ complete }'
:stripe='stripeKey'
:options='stripeOptions'
#change='complete = $event.complete'
/>
<button class='pay-with-stripe' #click='pay' :disabled='!complete'>Submit Payment Details</button>
<br>
</div>
script section with relavent added
import { Card, createToken } from 'vue-stripe-elements-plus'
import axios from 'axios';
export default {
components: { Card },
data() {
return {
errorMessage: null,
successMessage: null,
complete: false,
stripeKey: process.env.VUE_APP_STRIPE_PUB_KEY,
stripeOptions: {
// see https://stripe.com/docs/stripe.js#element-options for details
hidePostalCode: true
},
current: {
stripe: {
plan: null,
last4: null
}
},
}
},
methods: {
pay () {
createToken().then(result => {
axios.post('/billing/updateCard', {
token: result.token,
})
.then(res => {
if(res.data.success == true) {
this.successMessage = res.data.message
console.log(res.data.message)
}
if(res.data.success == false) {
this.errorMessage = res.data.message // Display error message from server if an error exists
}
})
.catch((err) => {
if(err) console.log(err)
if(err) this.$router.push('/company/settings?success=false')
})
});
}
}
}
</script>
I have checked that the API key is actually in the data value by doing <p>{{ stripeKey }}</p> and seeing the value show up. So yes the key is there and the key is valid (tested copy/paste into my HTML/JS test)
created(){
this.key=process.env.VUE_APP_STRIPE_KEY;
}
try this, i used this piece of code in my project and it worked... the issue maybe is that your key is not yet initialized when card us rendered idk. maybe key isnt issue at all. try this and let me know if works and we will debug it together.

Unable to customize form errors because server is returning 422 Unprocessable Entity without returning errors

I'm working with Laravel and VueJS and for all of my post and put methods server returns the newly created data after submitting the form, in the case of errors, I cannot access them from the browser console. This is what I can see in the newtwork tab.The purpose is to customize form errors according to errors that is being returned by the server
Here is my backend code :
private function validateForm($data){
return Validator::make($data,
[
'fname' => ['required', 'string','min:2' ,'max:255'],
'lname' => ['required', 'string','min:2' ,'max:255'],
// 'mname' => ['string','min:2' ,'max:255'],
'company' => ['string','min:2' ,'max:255'],
'title' => ['string','min:2' ,'max:255'],
'phone_number' => ['string','min:13' ,'max:13'],
'city' => ['required', 'string','min:2' ,'max:100'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed']
// 'password_confirm'=>['required','string']
]
)->validate();
}
//Register
public function register(Request $request){
$data=$this->validateForm($request->all());
$data['password']=Hash::make($data['password']);
$user=new User($data);
$user->save();
return response()->json($user);
}
And my code from the front-end:
export default{
data(){
return {
form:{
email:'',
password:'',
password_confirmation:'',
fname:'',
lname:'',
city:''
},
formError:''
}
},
methods:{
//This should be a POST method through axios
register:async function(){
try{
const res=await axios.post('api/register',
{
email:this.form.email,
password:this.form.password,
password_confirmation:this.form.password_confirmation,
fname:this.form.fname,
lname:this.form.lname,
city:this.form.city
});
//Une fois inscrit,il est redirige vers la page de login
this.$router.push({path:'/login'});
console.log("My data : ",res.data);
}catch(err){
console.log("Errors",err);
}
}
}
}
When there are no errors, everything goes fine, but when there are errors, this is what I get in the browser console tab:
And in the Devtools network tab
I've tried the following link Issues with Axios catch method from Laracast
how to display the errors in .catch coming from an api on frontend
And some others solution,but all of them didn't solve my problem.
Before using async-await pattern i used axios.post('url',data).then(res=>...).catch(err=>...)
When i use postman,http status is still 422 but the error object is returned,so with postman everything goes fine but not in the browser
How can i solve this problem?
Laravel returns the HTTP 422 - Unprocessable Entity when the validations you set fail. In your case I would take a closer look at the data you're posting to the server and manually check if it passes the validation cases you wrote.
To get the exact fields that are causing the error you need to handle this in your code, like this for example:
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
// 500 is the HTTP Status Code you want to return.
// This should also throw you in the catch branch of your front-end code
return response()->json(['errors'=>$validator->errors()], 500);
}
In your code the $data variable from the register function should be checked if it fails validation and return the error
This is because err will return the toString() method when accessed directly, but has properties:
err.response.data will have what you're looking for.
When there's an HTTP error (e.g. a response code between 400 and 599) axios returns an axios error response and in the repository documentation under error handling it indicates that you can access the actual response using error.response.data. For example:
try {
const res=await axios.post('api/register',
{
email:this.form.email,
password:this.form.password,
password_confirmation:this.form.password_confirmation,
fname:this.form.fname,
lname:this.form.lname,
city:this.form.city
});
//Une fois inscrit,il est redirige vers la page de login
this.$router.push({path:'/login'});
console.log("My data : ",res.data);
}catch(err){
if (err.response && err.response.status === 422) {
if (err.response.data.errors.fname) {
console.log('First name errors: '+ err.response.data.errors.fname.join(','));
}
// and so on
}
}
When Axios throws an error, the HTTP response can be found in error.response. Validation errors will be in the errors key, so you can access validation errors like this:
axios.post(someUrl, someData)
.then(response => {
// Successful response
})
.catch(error => {
let errors = error.response.data.errors;
});

AngularFire2 Firebase update object without causing other subscriptions to update

I just have a question to find out if this is possible:
So what I am doing is when I submit a post I wait for it to complete then update the user object in firebase to insert a time-stamp.
This is fine and works but when the time-stamp is inserted it is causing other subscriptions that are subscribed to changes in the user object to update.
What I want to do it update the user object without causing other subscribers to be updated.
Here is where I am updating the timestamp:
I tried commenting out this line of code which stops the data duplication issue on screen but I need this code to run as I need to update the timestamp when a post is submitted.
this.af.database.object('users/' + x[0].uid + '/lastPostAt').set(timestamp)
.then(x => { this.dialogsService.showSuccessDialog('Post Submitted'); });
Here is where I am subscribing to all the posts:
subscribeAllPosts(): Observable<Post[]> {
return this.af.database.list('/posts')
.map(Post.fromJsonList);
}
Here is where I am creating the array of posts in my constructor to display via a loop in the html:
this.activeItem = this.items[0];
this.postsService.subscribeAllPosts()
.subscribe(posts => {
let container = new Array<PostContainer>();
for (let post of posts) {
this.getEquippedItemsForUsername(post.username).subscribe(
x => {
try {
container.push(new PostContainer(post, x[0].equippedItems));
} catch (ex) { }
}
);
}
this.postContainers = container;
});
In the inner subscription it gets the equippedItems for the user of the post:
getEquippedItemsForUsername(username: string) {
return this.usersService.subscribeUserByUsername(username);
}
Which in turns calls:
subscribeUserByUsername (username: string) {
return this.af.database.list('users' , {
query: {
orderByChild: 'username',
equalTo: username
}
});
}
In the HTML it loops through the postContainer[]:
<li *ngFor="let item of postContainers">
So all that works the issue as stated is that if I do not have the following commented out then the posts will be duplicated more and more as the posts are submitted. If I refresh the app then the posts will show the correct non duplicated posts until another post is submitted.
this.af.database.object('users/' + x[0].uid + '/lastPostAt').set(timestamp)
.then(x => { this.dialogsService.showSuccessDialog('Post Submitted'); });
EDIT: Solved by splitting up logic.

Jquery ajax not working (Laravel 4)

I use jquery ajax to add data to database. When i click submit button, my page return blank. I use firebug to debug and see message: 500 (Internal Server Error).
routes.php
Route::controller('subscribers', 'SubscribersController');
SubscribersController.php
class SubscribersController extends \BaseController {
//The method to show the form to add a new feed
public function getIndex() {
//We load a view directly and return it to be served
return View::make('subscribe_form');
}
//This method is to process the form
public function postSubmit() {
//We check if it's really an AJAX request
if(Request::ajax()) {
$validation = Validator::make(Input::all(), array(
//email field should be required, should be in an email
//format, and should be unique
'email' => 'required|email|unique:subscribers, email'));
if($validation->fails()) {
return $validation->errors()->first();
} else {
$create = Subscribers::create(array(
'email' => Input::get('email')
));
//If successful, we will be returning the '1' so the form
//understands it's successful or if we encountered an unsuccessful creation attempt,
//return its info
return $create?'1':'We could not save your address to our system, please try again later';
}
} else {
return Redirect::to('subscribers');
}
}
}
view file:
{{--Form Starts Here --}}
{{Form::open(array('url' => URL::to('subscribers/submit'), 'method' => 'post'))}}
<p>Simple Newsletter Subscription</p>
{{Form::text('email', null, array('placeholder'=>'Type your E-mail address here'))}}
{{Form::submit('Submit!')}}
{{Form::close()}}
{{--Form Ends Here --}}
{{--This div will show the ajax response --}}
<div class="content"></div>
{{-- Because it'll be sent over Ajax, we add the jQuery source --}}
{{HTML::script('http://code.jquery.com/jquery-1.11.0.min.js') }}
<script type="text/javascript">
//Even though it's on footer, I just like to make
//sure that DOM is ready
$(function() {
//We hide de the result div on start
$('div.content').hide();
//This part is more jQuery related. In short, we make an Ajax post request and get
//the response back from server
$('input[type="submit"]').click(function(e) {
e.preventDefault();
$.post('http://localhost/laravel-blueprint/newsletter/public/subscribers/submit', {email: $('input[name="email"]').val()
}, function($data) {
if($data == '1') {
$('div.content')
.hide()
.removeClass('success error')
.addClass('success')
.html('You\'ve successfully subscribed to our newsletter')
.fadeIn('fast');
} else {
//This part echos our form validation errors
$('div.content')
.hide().removeClass('success error')
.addClass('error')
.html('There has been an error occurred: <br /><br />'+$data)
.fadeIn('fast');
}
});
});
//We prevented to submit by pressing enter or any other way
$('form').submit(function(e) {
e.preventDefault();
$('input[type="submit"]').click();
});
});
</script>
i use laravel 4
log-access:
127.0.0.1 - - [11/Mar/2014:17:54:41 +0700] "POST /laravel-blueprint/newsletter/public/subscribers/submit HTTP/1.1" 500 381
Any solution?
In order for your code to work, do the following changes:
SUBSCRIBERS CONTROLLER
class SubscribersController extends \BaseController {
public function getIndex() {
return View::make('subscribe_form');
}
public function postSubmit() {
if(Request::ajax()) {
$validation = Validator::make(Input::all(),
['email' => 'required|email|unique:subscribers,email']);
if($validation->fails()) {
return $validation->errors()->first();
} else {
// Note here that the model is Subscriber and not Subscribers
// This is the default convention for the subscribers table
$create = Subscriber::create(array(
'email' => Input::get('email')
));
return $create ? '1' : 'We could not save your address';
}
} else {
return Redirect::to('subscribers');
}
}
}
IMPORTANT FOR SUBSCRIBER MODEL
class Subscriber extends Eloquent {
// I don't know if you have timestamps enabled, but if not this is necessary
public $timestamps = false;
// Must be present for mass assignment to work (Subscriber::create)
protected $fillable = array('email');
}
Comment
500 (Internal Server Error) might be caused due to a PHP fatal.
Do you have error_reporting on?
If not, try
error_reporting(E_ALL); ini_set('display_errors', 1);
and check.

Categories

Resources