Vue undefined property Id when using Laravel Echo - laravel

I'm learning Vue2 and currently, I have a simple boilerplate using Laravel, Vue2, Laravel Echo, Sanctum, and the Websockets package, all using the Laravel default Echo setup. Everything works nicely there.
Now I'm trying to decouple things, so I've created the same boilerplate but as a Vue SPA and using Laravel Passport (I have my reasons for decoupling things and for using Passport). Everything works fine there as well, including a timeline I've added, but not the real-time stuff.
I need to pass the user id with the Echo event in a few places, so I created a global user object in main.js, like this (I'm using namespaced modules):
let User = store.state.auth.user
Vue.prototype.$user = User
But every time I try passing the user id to an event, the id is undefined, so Pusher cannot authenticate the channel. Though if I console log the user from within any component, I can see the user object with the id. I can also see the event in the Websockets dashboard. So everything works as normal, except passing the id. If I do this:
Echo.private(`timeline.${this.$user.id}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
The results is this:
private-timeline.undefined
I've also tried other syntax, such as:
Echo.private('timeline.'+this.$user.id)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
I'm having a difficult time trying to determine what I'm missing to be able to pass the id.

Try to use a function to defer, instead of an assignment. It is not defined during the assignment.
Vue.prototype.$getUser = ()=>store.state.auth.user
Echo.private(`timeline.${this.$getUser().id}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
or access the store directly.
Echo.private(`timeline.${this.$store.state.auth.user.id}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})
Or even better, use a getter in your store. (I will leave it to you to add the getter...)
Echo.private(`timeline.${this.$store.getters.userId}`)
.listen('.PostWasCreated', (e) => {
this.PUSH_POSTS([e])
})

Related

Managing profile members dataset in wix, to add when text being clicked email in an other category

i was trying to create once logged in the website a function onClick() in the member area. When text clicked would let add the user email in another role and enable user to other functions. I've tried with the code below, but it's not adding user email to the other role(ideas to fix it?). However, what's your opinion? maybe it could be better to let two different types of log in/register when in registration phase? (If answer is yes, how could i do that?)
`import wixUsers from 'wix-users';
import {roles} from 'wix-users-backend';
export function text67_click(event) {
/* This function was added from the Properties & Events panel. To learn
more, visit http://wix.to/UcBnC-4 */
// Add your code for this event here:
function getUser(loginEmail){this}
function assignRole(consulente, loginEmail) {
return roles.assignRole(consulente, loginEmail, { suppressAuth: false })
.then( () => {
console.log("Role assigned to member");
})
.catch((error) => {
console.log(error);
});
}
}`
Thanks in advance, for your opinions
you are trying to run backend function on frontedn. wix isnt allow it: "Member roles help you manage which site members can access certain pages. The Roles APIs allow you to manage the members assigned as holders of each role from your site's backend code." see here
to learn how to call backend function from frontend see here

Good practices to manage user session data with vue and laravel API

I am building a single-page application with Vue and laravel API as backend.
I've tried some packages like Vue Session and it worked well, however in almost every API call I always need to send 2 or 3 parameters that will always be the same (stored in vue-session), like user_id and company_id. I used to manage this with common PHP sessions (Zend_Session with Zend Framework) in my other applications, this way I always have that information stored in my backend session and don't need to send it every time by the frontend
Here's an example of how I used to do it with PHP session
$model->insert(array(
'user_id' => $this->session->user_id, //stored in session
'company_id' => $this->session->company_id, //stored in session
'field1' => $this->getParam('field1'), //frontend param (ajax)
'field2' => $this->getParam('field2') //frontend param (ajax)
));
And here's how I'm doing it with Vue and Laravel
const data = {
user_id: this.$session.get('user_id'), //this is what i'm trying to get rid of
company_id: this.$session.get('company_id'), //this is what i'm trying to get rid of²
field1: this.field1,
field2: this.field2
}
axios
.post('/api/some/endpoint', this.data)
.then(resp => {
//...//
})
Basically, in this example I want to not need to always send user_id and company_id as a post param.
Is there any way to get better code "reuse" in cases like this?
1, You can save your session data in the cookie. The browser will automatically send your cookie to the server. Don't forget to delete the cookie when the user logout.
2, If you still want to use Vue session or other storages, you can easily create a method that wraps your post method and add user's information to the payload
function postRequest(url, payload) {
payload.user_id = this.$session.get('user_id')
payload.company_id = this.$session.get('company_id')
return axios.post(url, payload)
}
Use this method whenever you want to make a post.

Vue router navigation guard prevent url from being changed

I'm using a vuejs navigation guard to do some checks to check if a user is valid to enter a page. If the user doesn't meet the criteria I want the auth guard to return false which it currently does. However, when this is done the browser url gets set back to the previous url I came from. I don't want this behaviour instead I want the browser url to stay the same but still keep the user unable to use the page.
The reason I want this is because when the user hits refresh I want it to stay on the same page. I know this is intended vuejs behaviour for the router but I'm hoping to find a way around it. Here is the code for auth guard.
function guardRoute (to, from, next) {
if (window.$cookies.get('kiosk_mode') === new DeviceUUID().get()) {
return next(false)
}
return next()
}
To reject a navigation but to not reset the url to its previous state you can reject the navigation with (requires vue 2.4.0+):
next(new Error('Authentication failure'));
And if you don't have router error handling then you need to include:
router.onError(error => {
console.log(error);
});
See documentation for more details: https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards
Try this
history.pushState({}, null, '/test') before the return next(false);

canActivate routeguard with nested observables using switchmap operator works only from browser

I am using firebase with authentication and firestore. Authenticated users are stored in database upon signup with extra roles field where some user have 'admin' role. I want to protect the admin route and i use the canActivate route guard. In the canActivate function I use 2 observables. The first 1 gets the logged in user and nested in that another observable which gets the saved users from firestore, uses the imformation from there o cehck if the logged in user is admin or not. The problem is that the routeguard works fine when the browser refreshes after the route types in the broser but when the route is called with the routerlink on the button, nothing happens.
tried using sycnronous values but those work only once and stop working after navigating around.
The canActivate function:
https://i.imgur.com/Rf0BZ79.png
canActivate(router: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.afAuth.getStateOnly().pipe(switchMap(user => { return this.db.getRole(user.uid) }))
}
The observables used:
https://i.imgur.com/hRp8zyf.png
https://i.imgur.com/oV56AGl.png
// user object or null from firebase
getStateOnly() {
return this.afAuth.authState
}
//checking the role and returning true or false(userArr is an array of users observable to store the users from firestore)
getRole(uid: string): Observable<boolean> {
return this.userArr.pipe(map(users => {
return users.filter(user => {
if (user.uid === uid) {
return user
}
})[0].roles.includes('admin')
}))
So this works only when i type the path in the browser and the browser refreshes when loading the route. It is not working when i click the admin button to navigate to admin page (not with routerLink nor router.navigate(..))
image of new canActivate() I have managed to solve the problem but i am still not sure why the previous implementation did not work..firebase is wierd sometimes. So I made a new observable which gets the users from firestore and i was transforming that output directly in the can activate function, see image.
Previously i got the users, transformed it and i called the transformed observable from the canactivate function wich did not seem to work. So it was something wrong with the data stream.

Using custom WP-API endpoints with the included Backbone JS client library

So I have created a custom endpoint using WP-API plugin. When testing with Postman, the endpoint works as expected.
The problem is that when I try to access the custom enpoint using the built in Backbone JS client, I cannot see my new endpoints in the wp.api.models object.
I have been digging and I think I have to send initialise it with a different schema or something, but have aboslutely no idea how to and can't find any info on how to extend wp.api.models so I can access my custom methods.
Example plugin code:
function my_awesome_func( $data ) {
return 'A STRING';
}
function initrest() {
register_rest_route( 'wp/v2', '/score', array(
'methods' => 'GET',
'callback' => 'my_awesome_func',
));
}
add_action( 'rest_api_init', 'initrest');
Example template code:
window.onload = function() {
console.log(wp.api.models);
};
This ouputs a list of the common models for Post, Comment, Tags etc, but no sign of my 'scores' endpoint.
Try initializing the wp api with your own route.
wp.api.init({'versionString' : 'custom-route/v1/', 'apiRoot': 'http://my-website.com/wp-json/'}).done(function()
{
console.log(wp.api.models);
});
Whereas versionString and apiRoot need to be replaced with your own data.
I'm afraid custom endpoints don't make into the wp.api.models by design of the Backbone client. Have a look to my question and the respective answers. They boil down to: "use a different client".
I use node-wpapi.

Resources