How to parse slug from url using route of laravel to vue components - laravel

I want to parse data to show product by using slug from laravel show route resource (get) to vue js components by using laravel api
example: https://shop.app/product/slug-name
i want to parse the slug-name into the vue components
export default {
name: 'product',
mounted() {
// console.log('Component mounted.')
this.fetchData()
},
data(){
return{
products: [],
product: {
id: '',
name: '',
slug: '',
description: '',
image: '',
created_at: '',
updated_at: ''
}
}
},
methods: {
fetchData(){
axios.get('/api/products')
.then((res) => {
this.products = res.data
})
.catch((err) => {
console.log(err)
})
}
}
}
i expect the output from showing the slug name, not show all the products

You can get you current url by
let currentUrl = window.location.pathname;
and then you can use lodash library its already included in laravel if you see you boostrap.js file
let ar = _.split(currentUrl, '/');
it will return your array. its just like explode in php. you can read about this here
and at last, get your product by
this.productName = _.last(ar);
`_.last` Its will just give you last element of your array which is your product. [here][2] is the documentation
you can make a method for this. like below
getProductSlug(){
let currentUrl = window.location.pathname;
let ar = _.split(currentUrl, '/');
return _.last(ar);
},

If you are using Laravel Routes you can get your slug in to your Vue instance like
var slugName = '{{ $slug }}';
export default {
name: 'product',
methods: {
fetchData(){
//you can use slugNname here
axios.get('/api/products/' + slugName)
.then((res) => {
this.products = res.data
})
.catch((err) => {
console.log(err)
})
}
}
after that you can use slugName in your axios request
hope it helps

Related

store results from method in data form

I am going to preface this with I have NOT done this in a LONG time and my mind is mud. So no picking on me just remind me what I am doing wrong or not remembering.
NOTE: This is VueJS 3 / Tailwind 3 inside a Laravel 9 Jetstream Project
I have a method...
locatorButtonPressed() {
navigator.geolocation.getCurrentPosition(
position => {
console.log(position.coords.latitude);
console.log(position.coords.longitude);
},
error => {
console.log(error.message);
},
)
},
and I have a form data
data() {
return {
form: this.$inertia.form({
name: '',
email: '',
password: '',
password_confirmation: '',
birthdate: '',
user_latitude: '',
user_longitude: '',
user_city: '',
user_region: '',
user_country: '',
location: '',
terms: false,
})
}
}
I want to store position.coords.latitude and position.coords.longitude from the method in the form Data under user_latitude and user_longitude respectfully.
What am I forgetting???
The data properties can be accessed via this.PROPERTY_NAME. For example, to set form.user_latitude, use this.form.user_latitude = newValue.
export default {
methods: {
locatorButtonPressed() {
navigator.geolocation.getCurrentPosition(
position => {
this.form.user_latitude = position.coords.latitude;
this.form.user_longitude = position.coords.longitude;
})
},
}
}
demo

Laravel Sanctum + Vue Auth

I have an API that is secured using Laravel Sanctum. In the front-end I managed to login with sanctum and a new bearer token is issued. So far so good but how can I store the token (without Vuex) to local storage and how I tell axios to use that token for any future requests ?
My code is as follows:
// AuthController.php
public function login(Request $request)
{
$fields = $request->validate([
'email' => 'required|string',
'password' => 'required|string'
]);
$user = User::where('email', $fields['email'])->first();
$token = $user->createToken('login_token')->plainTextToken;
if (!$user || !Hash::check($fields['password'], $user->password)) {
return response([
'message' => 'Invalid Login Credentials'
], 401);
}
$response = [
'user' => $user,
'token' => $token
];
return response($response, 201);
}
// Login.vue
export default {
methods: {
handleLogin() {
axios.get("/sanctum/csrf-cookie").then(response => {
axios.post("/api/login", this.formData).then(response => {
if (response.status === 201) {
this.$router.push({ path: "/" });
}
console.log(response);
});
});
}
},
data: function() {
return {
logo: logo,
formData: {
email: "",
password: ""
}
};
}
};
The login works fine, it is returning the expected results but I don't know how to store the generated token and how to send it to any future axios requests.
Thanks.
*** UPDATE ***
Ok so I figured it out how to send the headers and I'm doing it like so:
axios
.get("/api/expenses/", {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + "6|cnuOY69grhJiZzxEHoU74PapFkkcJeqbf3UiKx8z"
}
})
.then(response => (this.expenses = response.data.data));
}
The only remaining bit to this is how can I store the token to the local storage because right now, for testing purposes I hard coded the token.
In your Login.vue script
methods:{
loginUser(){
axios.post('/login',this.form).then(response =>{
localStorage.setItem('token', response.data.token) //store them from response
this.alerts = true
this.$router.push({ name: 'Dashboard'})
}).catch((errors) => {
this.errors = errors.response.data.errors
})
},
}
In your logged in file lets call it Dashboard.vue in <script>,
data(){
return {
drawer: true,
user: {roles: [0]},
token: localStorage.getItem('token'), //get your local storage data
isLoading: true,
}
},
methods: {
getUser(){
axios.get('/user').then(response => {
this.currentUser = response.data
this.user = this.currentUser.user
}).catch(errors => {
if (errors.response.status === 401) {
localStorage.removeItem('token')
this.$router.push({ name: 'Login'})
}
}).finally(() => {
setTimeout(function () {
this.isLoading = false
}.bind(this), 1000);
})
},
},
created(){
axios.defaults.headers.common['Authorization'] = `Bearer ${this.token}` //include this in your created function
this.getUser()
this.isCreated = true
}
I hope it works well for you
Ok so this is how I sorted this out.
Storing the token in the local storage:
localStorage.setItem("token", response.data.token);
Using the token when sending an axios call to the api:
const token = localStorage.getItem("token");
axios
.get("/api/endpoint/", {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + token
}
})
.then(response => (this.expenses = response.data));
}

post request using axios on Laravel 7

i am trying to post request on server by axois but unfortunately page is refreshing on button click how can i resolve this issue please help me thanks.
html view
axois script
<script>
$(document).ready(function(){
$("#prospects_form").submit(function(e) {
let url = "{{route('home.store')}}";
var name =$("#name").val();
var email =$("#email").val();
axios.post(url, {
params:{
name: 'name',
email:'email'
}
}).then((res)=>{
console.log(res);
}).catch(function(err){
console.log(err);
});
});
});
</script>
Route
Route::post('/home/store', 'HomeController#store')->name('home.store');
controller
public function store(Request $request)
{
$this->validate(
$request,
[
'name' => 'required',
'email' => 'required|email|unique:subscribes,email',
],
[
'name.required' => 'Name is required',
'email.required' => 'Email is required'
]
);
$subscribes = new Subscribe();
$subscribes = $request->name;
$subscribes = $request->email;
return response()->json($subscribes, 200);
}
axios send data in body not in params ref link https://github.com/axios/axios#note-commonjs-usage
axios.post(url, {
name: 'name',
email:'email'
}).then((res)=>{
console.log(res);
}).catch(function(err){
console.log(err);
});
params is used for get request
and to not refresh on form submit you can try
$("#prospects_form").submit(function(e) {
e.preventDefault()
and you need to preventDefault form action so u can submit form via ajax
so your final code will be
<script>
$(document).ready(function () {
$("#prospects_form").submit(function (e) {
e.preventDefault();
let url = "{{route('home.store')}}";
var name = $("#name").val();
var email = $("#email").val();
axios
.post(url, {
name: name,
email: email,
})
.then((res) => {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
});
});
</script>
Use e.preventDefault(); Like given below
<script>
$(document).ready(function(){
$("#prospects_form").submit(function(e) {
e.preventDefault();
let url = "{{route('home.store')}}";
var name =$("#name").val();
var email =$("#email").val();
axios.post(url, {
params:{
name: 'name',
email:'email'
}
}).then((res)=>{
console.log(res);
}).catch(function(err){
console.log(err);
});
});
});
</script>

How to search through JSON response with Cypress assertions

Considering the below API response I would like to assert the exact location of a certain value in a JSON structure. In my case the name of pikachu within forms:
"abilities": [
{
"ability": {
"name": "lightning-rod",
"url": "https://pokeapi.co/api/v2/ability/31/"
},
"is_hidden": true,
"slot": 3
},
{
"ability": {
"name": "static",
"url": "https://pokeapi.co/api/v2/ability/9/"
},
"is_hidden": false,
"slot": 1
}
],
"base_experience": 112,
"forms": [
{
"name": "pikachu",
"url": "https://pokeapi.co/api/v2/pokemon-form/25/"
}]
I would like to extend below code snippet to not scan the entire body as a whole as there are a lot of name's in the response, but rather go via forms to exactly pinpoint it:
describe('API Testing with Cypress', () => {
var baseURL = "https://pokeapi.co/api/v2/pokemon"
beforeEach(() => {
cy.request(baseURL+"/25").as('pikachu');
});
it('Validate the pokemon\'s name', () => {
cy.get('#pikachu')
.its('body')
.should('include', { name: 'pikachu' })
.should('not.include', { name: 'johndoe' });
});
Many thanks in advance!
Getting to 'forms' is just a matter of chaining another its(), but the 'include' selector seems to require an exact match on the object in the array.
So this works
it("Validate the pokemon's name", () => {
cy.get("#pikachu")
.its("body")
.its('forms')
.should('include', {
name: 'pikachu',
url: 'https://pokeapi.co/api/v2/pokemon-form/25/'
})
})
or if you just have the name,
it("Validate the pokemon's name", () => {
cy.get("#pikachu")
.its("body")
.its('forms')
.should(items => {
expect(items.map(i => i.name)).to.include('pikachu')
})
})
and you can assert the negative,
.should(items => {
expect(items.map(i => i.name)).to.not.include('johndoe')
})
Can you try the below code and see if it helps with your expectation. From the response you could get the name as below;
describe('API Testing with Cypress', () => {
var baseURL = "https://pokeapi.co/api/v2/pokemon"
beforeEach(() => {
cy.request(baseURL+"/25").as('pikachu');
});
it('Validate the pokemon\'s name', () => {
cy.get('#pikachu').then((response)=>{
const ability_name = response.body.name;
expect(ability_name).to.eq("pikachu");
})
});
})

Laravel passport & Vue login

I've made login function in laravel with passport api and I'm getting status 200, the issue is that i don't know how to login the user and redirect to homepage after this successful request (I'm using vuejs component).
Code
controller
public function login(Request $request)
{
$credentials = [
'email' => $request->email,
'password' => $request->password
];
if (Auth::attempt($credentials)) {
// $token = auth()->user()->createToken('AppName')->accessToken;
// $success['token'] = $token;
// $success['name'] = auth()->user()->name;
// $success['id'] = auth()->user()->id;
$user = Auth::user();
$success['token'] = $user->createToken('AppName')->accessToken;
$success['user'] = $user;
return response()->json(['success'=>$success], 200);
} else {
return response()->json(['error' => 'UnAuthorised'], 401);
}
}
component script
<script>
import {login} from '../../helpers/Auth';
export default {
name: "login",
data() {
return {
form: {
email: '',
password: ''
},
error: null
};
},
methods: {
authenticate() {
this.$store.dispatch('login');
axios.post('/api/auth/login', this.form)
.then((response) => {
setAuthorization(response.data.access_token);
res(response.data);
})
.catch((err) =>{
rej("Wrong email or password");
})
}
},
computed: {
authError() {
return this.$store.getters.authError;
}
}
}
</script>
Auth.js (imported in script above)
import { setAuthorization } from "./general";
export function login(credentials) {
return new Promise((res, rej) => {
axios.post('/api/auth/login', credentials)
.then((response) => {
setAuthorization(response.data.access_token);
res(response.data);
})
.catch((err) =>{
rej("Wrong email or password");
})
})
}
general.js (imported in script above)
export function setAuthorization(token) {
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`
}
Question
How can I login my user after successful request?
...........................................................................................................................................................
Say that you have defined a vuex auth module with a login action
that accepts a credentials object.
If success it receives a response that contains the access_token our API granted to the user.
We store/commit the token and also update axios settings to use that token on each of the following requests we make.
import axios from 'axios';
const state = {
accessToken: null,
};
const mutations = {
setAccessToken: (state, value) => {
state.accessToken = value;
},
};
const getters = {
isAuthenticated: (state) => {
return state.accessToken !== null;
},
};
const actions = {
/**
* Login a user
*
* #param context {Object}
* #param credentials {Object} User credentials
* #param credentials.email {string} User email
* #param credentials.password {string} User password
*/
login(context, credentials) {
return axios.post('/api/login', credentials)
.then((response) => {
// retrieve access token
const { access_token: accessToken } = response.data;
// commit it
context.commit('setAccessToken', accessToken);
return Promise.resolve();
})
.catch((error) => Promise.reject(error.response));
},
};
Before every request to our API we need to send the token we received and store on our auth module therefore we define a global axios request interceptor on our main.js
import store from '#/store';
...
axios.interceptors.request.use(
(requestConfig) => {
if (store.getters['auth/isAuthenticated']) {
requestConfig.headers.Authorization = `Bearer ${store.state.auth.accessToken}`;
}
return requestConfig;
},
(requestError) => Promise.reject(requestError),
);
...
We then define our login component which on a success login redirects us to the dashboard page
<template>
<div>
...
<form #submit.prevent="submit">
...
<button>Submit</button>
</form>
...
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
data() {
return {
credentials: {
email: '',
password: '',
},
};
},
methods: {
...mapActions('auth', [
'login',
]),
submit() {
this.login({ ...this.credentials })
.then(() => {
this.$router.replace('/dashboard');
})
.catch((errors) => {
// Handle Errors
});
},
},
}
Finally we define our routes and their guards
import store from '#/store'
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'landing',
component: Landing,
// User MUST NOT BE authenticated
beforeEnter: (to, from, next) => {
const isAuthenticated = store.getters['auth/isAuthenticated'];
if (isAuthenticated) {
return next({
name: 'dashboard',
});
}
return next();
},
},
{
path: '/login',
name: 'login',
component: Login,
// User MUST NOT BE authenticated
beforeEnter: (to, from, next) => {
const isAuthenticated = store.getters['auth/isAuthenticated'];
if (isAuthenticated) {
return next({
name: 'dashboard',
});
}
return next();
},
},
{
path: '/dashboard',
name: 'dashboard',
component: Dashboard,
// User MUST BE authenticated
beforeEnter: (to, from, next) => {
const isAuthenticated = store.getters['auth/isAuthenticated'];
if (!isAuthenticated) {
return next({
name: 'login',
});
}
return next();
},
},
{ path: '*', redirect: '/' },
],
});
Now only users with an access token can have access to dashboard route and any child routes you may define in the future. (No further check is necessary as any child of this route will execute that guard).
If someone attempts to access dashboard route without an access token will be redirected to login page
If someone attempts to access landing or login page with an access token will be redirected back to dashboard.
Now what happens if on any of our future API requests our token is invalid?
we add a global axios response interceptor on our main.js and whenever we receive a 401 unathorized response we clear our current token and redirect to login page
import store from '#/store';
...
axios.interceptors.response.use(
response => response,
(error) => {
if (error.response.status === 401) {
// Clear token and redirect
store.commit('auth/setAccessToken', null);
window.location.replace(`${window.location.origin}/login`);
}
return Promise.reject(error);
},
);
...
Final Words
I believe that all of the above steps are enough to help you have a better understanding on how to use the access token. Of course you should also store the token on browsers localStorage so that the user doesnot have to login whenever experiences a page refresh and token gets clear from memory. And at least refactor router beforeEnter functions by moving them to a separate file to avoid repetition.

Resources