How to implement Custom Async Validator in Angular4 - validation

I'm applying Angular 4 in my project and I am having trouble with Custom Validation using HTTP request.
I also tried this: How to implement Custom Async Validator in Angular2.
But it doesn't work in my project.
Here's what I've done so far:
Validation biding:
userName: ['', [Validators.required, Validators.minLength(3), this.validateUserName.bind(this)]]
Value changes event:
let userNameControl = this.individualForm.get('userName');
userNameControl.valueChanges.subscribe(value => {
this.setErrorMessagesForUserNameControl(userNameControl)
}
);
Validation function:
validateUserName(control: FormControl): Promise<any> {
let promise = new Promise<any>(
(resolve, reject) => {
if (this.oldUserNameForCheck != undefined) {
this._individualUpdateService.isUserNameExisting(this.oldUserNameForCheck, control.value).subscribe(
(res) => {
if (res.isUserNameExisting) {
console.log("existing");
resolve({'existing': true});
} else {
console.log("NOT existing");
resolve(null);
}
},
(error) => {
console.log(error);
}
);
} else {
resolve(null);
}
}
);
return promise;
}
Error Messages
I just try to validate the username by sending it to the back-end.
Here's the logs
As you can see, there's a message for "required", "minlength". Those work fine. But the message for Custom validation is not quite clear.

Async validator should be in the next parameter
userName: ['',
[ Validators.required, Validators.minLength(3) ],
[ this.validateUserName.bind(this) ]
]
Also its better to have a factory method with required dependencies that would create validator, instead of using 'bind(this)'
userNameValidator(originalUsername, individualUpdateService) {
return (control: FormControl): Promise<any> => {
return new Promise<any>((resolve, reject) => {
if (originalUsername != undefined) {
individualUpdateService.isUserNameExisting(originalUsername, control.value).subscribe(
(res) => {
if (res.isUserNameExisting) {
console.log("existing");
resolve({ 'existing': true });
} else {
console.log("NOT existing");
resolve(null);
}
},
(error) => {
console.log(error);
}
);
} else {
resolve(null);
}
})
}
}
userName: ['',
[ Validators.required, Validators.minLength(3) ],
[ this.userNameValidator(this.oldUserNameForCheck, this._individualUpdateService) ]
]

Related

How to add custom header in NestJS GraphQL Resolver

I want to add custom header in the response of one of my GraphQL resolver Queries in Nestjs. here is the code.
#Query(() => LoginUnion)
async login(
#Args({ type: () => LoginArgs }) { LoginInfo: { email, password } } : LoginArgs
): Promise<typeof LoginUnion> {
try {
let userInfo = await this.userModel.findOne({ email, password: SHA256(password).toString() }, { 'password': false });
if (userInfo === null) {
return new CustomErrorResponse({ message: 'Wrong password or username'});
}
if (!userInfo.isVerified) {
return new CustomErrorResponse({ message: 'User in not verified'});
}
const token = await this.authentication.sign(userInfo, config.get('Secure_JWT_Sign_Key'));
// set header here
console.log('_DEBUG_ =>', token);
} catch(error) {
console.log('user.resolver.login => ', error);
return new CustomErrorResponse({ message: 'Server Exception', additonalInfo: JSON.stringify(error) });
}
}

IOs-How to handle in app purchase billing?

In order to implement in app purchase using expo am using https://docs.expo.io/versions/latest/sdk/in-app-purchases.
I implemented as per the document and i tested it in sandbox mode.what i have did is:
1)Set up in app purchase in appstore.
2)implement the functionality accordingly.
3)Validate receipt with cloud function and return the expiry date.
My question here is is there anything to do in our end regarding the billing?in sandbox mode if it is a fake transaction it didn't ask anything about payment.How it work in production is it differently and need we do anything for managing billing?
Any explanation, suggestions and corrections will be awesome.
My code is:
........
if (InAppPurchases.setPurchaseListener) {
InAppPurchases.setPurchaseListener(({ responseCode, results, errorCode }) => {
if (responseCode === InAppPurchases.IAPResponseCode.OK) {
results.forEach(purchase => {
if (!purchase.acknowledged) {
if (purchase.transactionReceipt) {
if (Platform.OS === "ios") {
if (!this.flag) {
this.flag = true;
fetch("url", {
method: "POST",
body: JSON.stringify(purchase),
headers: { "Content-type": "application/json;charset=UTF-8" }
})
.then(response => {
if (response.ok) {
return response.json();
}
})
.then(json => {
if (json && Object.keys(json).length) {
let subscriptionDetails = {};
subscriptionDetails.subscribed = json.isExpired;
subscriptionDetails.expiry = JSON.parse(json.expiryDate);
subscriptionDetails.inTrialPeriod = json.inTrial;
subscriptionDetails.productId = json.id;
SecureStore.setItemAsync(
"Subscription",
JSON.stringify(subscriptionDetails)
)
.then(() => {
console.info("subscription Saved:");
store.dispatch(
setWsData("isSubscriptionExpired", json.isExpired)
);
let expired = json.isExpired;
store.dispatch(setUiData("isCheckAnalyze", true));
store.dispatch(setWsData("firstSubscription", false));
this.setState({ checkExpiry: json.isExpired });
if (!expired) {
InAppPurchases.finishTransactionAsync(purchase, true);
alert("Now you are Subscribed!!");
} else {
alert("Expired");
}
})
.catch(error =>
console.error("Cannot save subscription details:", error)
);
}
})
.catch(err => console.log("error:", err));
}
}
}
}
});

Laravel vue stripe: how to pass client_secret PaymentIntent from clientside to serverside?

I'm using stripe with laravel and vue js. Stripe support told me that I have to implent the paymentIntent function. All the code works fine, the problem is that on the server side I have to pass the client_secre and I dont know how to do it...
Here's the code...
SERVER SCRIPT
\Stripe\Stripe::setApiKey('MY_KEY');
try {
\Stripe\PaymentIntent::create([
'currency' => 'EUR',
'amount' => $request->amount * 100,
'description' => 'Donazione',
'metadata' => [
'customer' => $request->name,
'integration_check' => 'accept_a_payment'
]
]);
CLIENT SIDE SCRIPT
import { Card, createToken } from 'vue-stripe-elements-plus'
export default {
components: { Card },
data () {
return {
complete: false,
errorMessage: '',
stripeOptions: {
// see https://stripe.com/docs/stripe.js#element-options for details
style: {
base: {
color: '#32325d',
lineHeight: '18px',
fontFamily: '"Raleway", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
},
hidePostalCode: true
}
}
},
methods: {
pay () {
//createToken().then(data => console.log(data.token))
// Instead of creatToken I have to use confirmCardPayment() and pass the client_secret
},
change(event) {
// if (event.error) {
// this.errorMessage = event.error.message;
// } else {
// this.errorMessage = ''
// }
this.errorMessage = event.error ? event.error.message : ''
}
}
}
I recently had to set this up in my platform and here is how I did it. I created a controller called:
PaymentIntentController.php
Stripe::setApiKey(env('STRIPE_SECRET'));
$payment_intent = PaymentIntent::create([
'payment_method_types' => ['card'],
'amount' => $request->invoice['total'] * 100,
'currency' => $this->currency($request),
'receipt_email' => $request->invoice['clients_email']
],
[
'stripe_account' => $request->user['stripe_user_id']
]);
return $payment_intent;
On the client-side, you need to have an Axios request hit this controller so you can get the payment_intent.
Like this:
loadPaymentIntent () {
axios.post('/api/stripe/connect_payment_intent', {'invoice': this.invoice, 'user': this.user}).then((response) => {
this.paymentIntent = response.data
})
},
I have my payment intent setup to load when a checkout form is displayed. Then when the form is submitted we have access to the payment_intent which we can use in the confirmCardPayment method like such:
submit () {
let self = this
self.isLoading = true
self.stripe.confirmCardPayment(self.paymentIntent.client_secret, {
return_url: self.returnUrl + `/clients/${self.invoice.client_id}/invoices/${self.invoice.id}`,
receipt_email: self.invoice.clients_email,
payment_method: {
card: self.card,
billing_details: {
name: self.formData.name,
}
}
}).then(function(result) {
if (result.error) {
self.isLoading = false
self.cardError.status = true
self.cardError.message = result.error.message
setTimeout(() => {
self.cardError = {}
}, 3000)
} else {
if (result.paymentIntent.status === 'succeeded') {
self.handleInvoice(result.paymentIntent)
self.closeModal()
setTimeout(() => {
location.href = self.returnUrl + `/clients/${self.invoice.client_id}/invoices/${self.invoice.id}?success=true`
}, 1000)
}
}
});
},

issue with slowly geting data from api to vue view

I have issue with very slowly getting data from laravel api to vue view, I did tutorial where I have:
import axios from 'axios';
const client = axios.create({
baseURL: '/api',
});
export default {
all(params) {
return client.get('users', params);
},
find(id) {
return client.get(`users/${id}`);
},
update(id, data) {
return client.put(`users/${id}`, data);
},
delete(id) {
return client.delete(`users/${id}`);
},
};
<script>
import api from "../api/users";
export default {
data() {
return {
message: null,
loaded: false,
saving: false,
user: {
id: null,
name: "",
email: ""
}
};
},
methods: {
onDelete() {
this.saving = true;
api.delete(this.user.id).then(response => {
this.message = "User Deleted";
setTimeout(() => this.$router.push({ name: "users.index" }), 1000);
});
},
onSubmit(event) {
this.saving = true;
api
.update(this.user.id, {
name: this.user.name,
email: this.user.email
})
.then(response => {
this.message = "User updated";
setTimeout(() => (this.message = null), 10000);
this.user = response.data.data;
})
.catch(error => {
console.log(error);
})
.then(_ => (this.saving = false));
}
},
created() {
api.find(this.$route.params.id).then(response => {
this.loaded = true;
this.user = response.data.data;
});
}
};
</script>
It's load data from api very slowly I see firstly empty inputs in view and after some short time I see data, if I open api data from laravel I see data immediately, so my question is How speed up it? Or maby I did something wrong?
Whenever I am using an API with Vue, I usually make most of my API calls before opening the Vue then passing it in like this.
<vue-component :user="'{!! $user_data !!}'"></vue-component>
But if you have to do it in the Vue component, I am not sure if this will show improvement over your method but I would set it up with the "mounted" like so.
export default {
mounted() {
api.find(this.$route.params.id).then(response => {
this.loaded = true;
this.user = response.data.data;
});
}
}
Also heres a good tutorial on Axios and how to use HTTP Requets with Vue.
Hopefully this answered your question, good luck!

Cannot set property 'clientMutationId' of undefined" Error

outputFields: {
token: {
type: GraphQLString,
resolve: (token) => token
}
},
outputfields never gets called, not sure whether i am doing in a right way or not, doesn't the resolve function gets called while returning data from mutateAndGetPayload method.
mutateAndGetPayload: (credentials) => {
console.log('credentials', credentials);
userprof.findOne({email: credentials.email}).exec(function(err, r) {
if(!r) {
return new Error('no user')
} else if(r) {
if(r.password != credentials.password) {
return new Error('password error');
} else {
var token = jwt.getToken(r);
console.log(token);
return {token};
}
}
});
}
I think that you need to return something from the mutateAndGetPayload method. That could be a promise. Try to return the userprof.findOne.
Solution
token: {
type: GraphQLString,
resolve: ({token}) => token
}
},
mutateAndGetPayload: (credentials) => {
return UserProf.findOne({ email: credentials.email }).then((r) => {
if (!r) {
return new Error('no user');
} else if (r) {
if (r.password != credentials.password) {
return new Error('password error');
} else {
return { token: jwt.getToken(r) };
}
}
});
}

Resources