MSAL doesn't recognize signIn() from Chrome Extension - vue.js

I am trying to make some API calls via MsGraph from Chrome-extension.I am using Vue2 to build this extension and 'vue-msal'. When I print msal object it gets in this format:
But when I call it I get nothing.It suppose to open a logIn window.
<div id="demo">
<div v-if="user">
<div>Welcome {{user.name}}</div>
<div v-if="user.profile.jobTitle">Your job title is {{user.profile.jobTitle}}</div>
<div><button #click="signOut()">logout</button></div>
</div>
<div v-else>
<button #click="signIn()"> Please sign-in</button>
</div>
</div>
</template>
<script>
import { msalMixin } from 'vue-msal';
export default {
mixins: [msalMixin],
name: 'HelloWorld',
mounted () {
},
computed: {
user() {
let user = null;
if (this.msal.isAuthenticated) { // Note that the dollar sign ($) is missing from this.msal
user = {
...this.msal.user,
profile: {}
}
if (this.msal.graph && this.msal.graph.profile) {
user.profile = this.msal.graph.profile
}
}
return user;
}
},
methods:{
async signIn(){
console.log(this.$msal,'msal')
console.log(this.$msal.signIn(),'signIn func')
},
signOut(){
this.$msal.signOut()
}
}
}
</script>

Related

Losing my data when i refresh page in vuejs

I'm creating a social network for project in my formation, i have a like system and it work.
i have a components cardArticle with all info and i try to do a like count. It work but when i refresh the page or going on other page, i lost all my data likes (my data is not saved)
components/CardArticle.vue
<template>
<div id="card">
<div>
<a class="cardLink">
<img class="card-img" v-if="post.imageUrl !== undefined" :src="post.imageUrl" />
<h2 class="cardTitle"> {{ post.title }}</h2>
<p class="cardDescription"> {{ post.description }}</p>
</a>
</div>
<div class="buttonIcon">
<div>
<button type="button" class="buttonDelete" id="buttonDelete" #click="deletePost"
v-if="this.post.userId === this.user.userId || this.user.isAdmin === true">Supprimer</button>
<button type="button" class="buttonEdit" id="buttonEdit" #click="modifyPost"
v-if="this.post.userId === this.user.userId || this.user.isAdmin === true">
Editer
</button>
</div>
<div class="divIconLike">
<div class="iconLike">
<a #click="sendLike">
<i class="fa-regular fa-thumbs-up"></i>
</a>
</div>
<div class="countLike">
<p> {{ likes }} </p>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
import router from "../router/index.js";
export default {
name: 'CardArticle',
data () {
return {
likes: 0
}
},
props: {
post: {
type: Object
}
},
computed: {
user() {
return this.$store.getters.user;
}
},
methods: {
sendLike() {
axios.post("http://localhost:3000/api/articles/" + this.post._id + "/like", {
userId: this.user.userId
}, {
headers: {
Authorization: "Bearer " + this.user.token
}
})
.then(response => this.likes = response.data.article.likes)
.catch(error => console.log(error))
}
}
}
</script>
views/home.vue
<template>
<div class="home" v-if="this.user.token !== null">
<CardArticle v-for="post in allPosts" v-bind:key="post.id" :post="post" />
</div>
</template>
<script>
import CardArticle from "../components/CardArticle.vue"
import axios from "axios";
export default {
name: 'HomeArticle',
data () {
return {
post: {
title: "",
description: "",
imageUrl: ""
},
allPosts: [],
}
},
computed: {
user() {
return this.$store.getters.user;
}
},
components: {
CardArticle,
},
mounted() {
axios.get("http://localhost:3000/api/articles", {
headers: {
Authorization: "Bearer " + this.user.token
}
})
.then(response => {
this.allPosts = response.data;
})
.catch(error => {
return error;
})
}
}
</script>
What i should do for not losing my data ?
I would not use vuex or localstorage for that if possible, you have idea ?
Thanks for your help
If you loading data from server, then refresh page, you always will be lose data, because browser loading page again from server, and application will load data again.
If you don't want use vuex (but why not?), you can write data to cookies (by setting cookie value), then load it on app startup (when page is loaded). But it's not best practice at all. You can use vue3-cookies lib (link).
By the way, better learn to use stores, most progressive, I think, is Pinia.
Check: https://pinia.vuejs.org/
i lost all my data likes (my data is not saved)
likes is belong to each articles and It should have been saved to your db and call API to retrieve it again on component mounting:
export default {
name: 'CardArticle',
data () {
return {
likes: 0 // It's not managed by component state
}
},
methods: {
sendLike() {
axios.post("http://localhost:3000/api/articles/" + this.post._id + "/like", {
userId: this.user.userId
}, {
headers: {
Authorization: "Bearer " + this.user.token
}
})
.then(
// invalidates, update allPosts props (emit to parent)
)
.catch(error => console.log(error))
}
}
}

How to emit component's method from router-view?

I have 50 models and for All model CRUDs, I would like to make toolbar for each page (like index, create, update, delete and etc.).
Look at this picture please:
My folder structure:
App.vue
<template>
<div id="app">
<ul class="nav">
<router-link to="/posts">Posts</router-link>|
<router-link to="/products">Products</router-link>|
</ul>
<hr>
<router-view class="content"/>
<hr>
<router-view name="toolbar" />
</div>
</template>
<script>
import Posts from "./views/posts/Index";
import Products from "./views/products/Index";
export default {
name: "App",
components: {
Posts,
Products
},
data() {
return {
status: "This is the default status message"
};
}
};
</script>
views/posts/Index.vue
<template>
<div class="w-full">
<div class="card-header">
<span>test</span>
</div>
</div>
</template>
<script>
export default {
methods: {
my_func(type) {
this.$notification[type]({
message: "Notification Title",
description: "This test."
});
}
}
};
</script>
views/posts/components/Toolbar.vue
<template>
<toolbar>
<toolbar-section>
<div class="toolbar-link">
<button></button>
</div>
</toolbar-section>
</toolbar>
</template>
<script>
export default {
data() {
return {
checked: null
};
},
methods: {
update: function() {
this.$emit("my_func");
}
}
};
</script>
Fiddle: https://codesandbox.io/s/trigger-event-views-165yz?fontsize=14
UPDATE
Now, I want when the user clicks on the edit button, I check the table and find the selected row and redirect to the update page and if a row does not select, something alerted.
You can have a another vue instance just for Events.
vueEventManager.js
import Vue from 'vue';
class vueEventManager {
constructor() {
this.vue = new Vue;
}
trigger(event, data = null) {
this.vue.$emit(event, data);
}
listen(event, callback) {
this.vue.$on(event, callback);
}
off(event, callback) {
this.vue.$off(event, callback);
}
once(event, callback) {
this.vue.$once(event, callback);
}
}
export default vueEventManager;
Then you can register it in your main.js file:
import vueEventManager from './folder/vueeventmanager';
window.Event = new vueEventManager();
Now you can use it in your components to emit events.
Event.trigger('eventName', {'valueName': value})
And listen to them
Event.listen('eventName', (value) => {
//do something
});

Vue.js Component emit

I have some problem about component $emit
This is my child component:
<template>
<div class="input-group mb-3 input-group-sm">
<input v-model="newCoupon" type="text" class="form-control" placeholder="code">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" #click="addCoupon">comfirm</button>
</div>
</div>
</template>
<script>
export default {
props: ["couponcode"],
data() {
return {
newCoupon: this.couponcode
};
},
methods: {
addCoupon() {
this.$emit("add", this.newCoupon);
}
}
};
</script>
This is parent component
<template>
<div>
<cartData :couponcode="coupon_code" #add="addCoupon"></cartData>
</div>
</template>
<script>
import cartData from "../cartData";
export default {
components: {
cartData
},
data() {
return {
coupon_code: ""
}
},
methods:{
addCoupon() {
const api = `${process.env.API_PATH}/api/${
process.env.CUSTOM_PATH
}/coupon`;
const vm = this;
const coupon = {
code: vm.coupon_code
};
this.$http.post(api, { data: coupon }).then(response => {
console.log(response.data);
});
},
}
}
</script>
When I click the 'confirm' button,the console.log display 'can't find the coupon' 。 If I don't use the component,it will work 。
What is the problem? It's about emit?
addCoupon() {
this.$emit("add", this.newCoupon); // You emitted a param
}
// then you should use it in the listener
addCoupon(coupon) { // take the param
const api = `${process.env.API_PATH}/api/${
process.env.CUSTOM_PATH
}/coupon`;
const coupon = {
code: coupon // use it
};
this.$http.post(api, { data: coupon }).then(response => {
console.log(response.data);
});
},

Vue-Dropzone processQueue not working

On my website you can upload a dog with attributes and images.
Vuejs is the frontend and Laravel the backend.
I am using this vue-dropzone component in my project to upload images.
The problem
I want to upload the images and the attributes of a dog at the same time (when the user clicks the submit button), so that the image files can be linked to the dog's id in the database.
Laravel function to register a new dog (route: 'api/dogs')
public function store(Request $request)
{
$attributes = [
'name' => $request->input('name'),
'type' => $request->input('dogType'),
...
];
$dogId = Dog::insertGetId($attributes);
// Upload files
if ($request->hasFile('files')) {
// getting all files
$files = $request->file('files');
// Count files to be uploaded
$file_count = count($files);
// start count how many uploaded
$uploadcount = 0;
if($uploadcount == $file_count) {
return true;
} else {
FileController::store($request, 0, 0, $dogId, $files, $uploadcount);
}
}
return $dogId;
}
Dropzone component (Formdropzone)
<template>
<div>
<dropzone
:id="this.id"
:url="this.url"
:accepted-file-types='"image/*"'
:use-font-awesome="true"
:preview-template="template"
:auto-process-queue="false" <----
:upload-multiple="true"
:parallel-uploads=100
:max-files=100
#vdropzone-success="showSuccess"
>
</dropzone>
</div>
</template>
<script>
import Dropzone from 'vue2-dropzone'
export default {
props: {
id: {
type: String,
required: true
},
url: {
type: String,
required: true
}
},
components: {
Dropzone
},
methods: {
showSuccess(file) {
console.log('A file was successfully uploaded')
},
template() {
return `
<div class="dz-preview dz-file-preview">
<div class="dz-image" style="width: 200px;height: 200px">
<img data-dz-thumbnail /></div>
<div class="dz-details">
<div class="dz-size"><span data-dz-size></span></div>
<div class="dz-filename"><span data-dz-name></span></div>
</div>
<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
<div class="dz-error-message"><span data-dz-errormessage></span></div>
<div class="dz-success-mark"><i class="fa fa-check"></i></div>
<div class="dz-error-mark"><i class="fa fa-close"></i></div>
</div>
`;
}
}
}
</script>
Register dog component
<tab-content title="Images">
<div class="form__input__wrapper">
<span class="label">Images (optional)</span>
<formdropzone url="http://domain.local/api/dogs" ref="dogDropzone" id="dogDropzone"></formdropzone>
</div>
</tab-content>
<script>
import Formdropzone from './Formdropzone'
export default {
data() {
return {
dog:{
name: '',
dogType: '',
...
}
}
},
methods: {
publish() {
this.$http.post('api/dogs', this.dog)
.then(response => {
this.$refs.dogDropzone.processQueue() <----
this.$router.push('/feed')
})
}
},
components: {
'formdropzone': Formdropzone
}
</script>
The error message
Uncaught (in promise) TypeError: Cannot read property 'processQueue' of undefined
I would be very thankful for any kind of help!

Vuejs DOM doesn't update after fetching data

I have bound an array events to a component tag <scheduler> containing events to fill in a scheduler app (dhtmlx scheduler). However, the DOM doesn't seeem to refresh itself when data is retrieved by the getEvents methods triggered when vue instance is created.
There is 2 vue files I work with: App.vue containing the main app component and the Scheduler.vue file containing the scheduler component.
The thing is that when I modify something in the Scheduler.vue file and save it, it correctly take the updated events array into account.
Scheduler parse the data in the events prop when DOM is mounted in scheduler component.
Therefore is there something I can do to get the updated array ?
Here is the App.vue:
<template>
<div id="app">
<div class="container">
<scheduler v-bind:events="events"></scheduler>
</div>
</div>
</template>
<script>
import Scheduler from './components/Scheduler.vue';
import auth from './components/auth/index'
import data from './components/data/index'
export default {
name: 'app',
components: {
Scheduler
},
data() {
return {
events: []
}
},
created() {
this.getEvents();
},
watch: {
events: function(value) {
console.log('updated');
}
},
methods: {
async getEvents() {
try {
const token = await auth.getToken(this);
const thattoken = await auth.getThatToken(this, token);
await data.getOgustData(this, token, '/calendar/events', 307310564, this.events);
} catch (e) {
console.log(e);
}
},
}
}
</script>
Here is Scheduler.vue:
<template lang="html">
<div ref="scheduler_here" class="dhx_cal_container" style='width:100%; height:700px;'>
<div class="dhx_cal_navline">
<div class="dhx_cal_prev_button"> </div>
<div class="dhx_cal_next_button"> </div>
<div class="dhx_cal_today_button"></div>
<div class="dhx_cal_date"></div>
<div class="dhx_cal_tab" name="day_tab" style="right:204px;"></div>
<div class="dhx_cal_tab" name="week_tab" style="right:140px;"></div>
<div class="dhx_cal_tab" name="month_tab" style="right:76px;"></div>
</div>
<div class="dhx_cal_header"></div>
<div class="dhx_cal_data"></div>
</div>
</template>
<script>
import 'dhtmlx-scheduler'
import 'dhtmlx-scheduler/codebase/locale/locale_fr';
import 'dhtmlx-scheduler/codebase/ext/dhtmlxscheduler_readonly.js';
export default {
name: 'scheduler',
props: {
events: {
type: Array,
default () {
return [{
id: '',
text: '',
start_date: '',
end_date: '',
}]
}
}
},
mounted() {
scheduler.config.xml_date = '%Y-%m-%d %H:%i';
// disable left buttons on lightbox
scheduler.config.buttons_left = [];
// enable cancel button on lightbox's right wing
scheduler.config.buttons_right = ['dhx_cancel_btn'];
// changing cancel button label
scheduler.locale.labels['icon_cancel'] = 'Fermer';
// hide lightbox in month view
scheduler.config.readonly_form = true;
// hide select bar in day and week views
scheduler.config.select = false;
scheduler.config.lightbox.sections = [
{
name: "description",
height: 20,
map_to: "text",
type: "textarea",
focus: true
}
];
scheduler.init(this.$refs.scheduler_here, new Date(), 'month');
scheduler.parse(this.$props.events, 'json');
},
}
</script>
<style lang="css" scoped>
#import "~dhtmlx-scheduler/codebase/dhtmlxscheduler.css";
</style>
getOgustData can't populate events in a way that Vue can observe. Since you're passing it as an argument, the array itself can be updated, but it's not a reactive array. Try
var newEvents;
await data.getOgustData(this, token, '/calendar/events', 307310564, newEvents);
this.events = newEvents;
Assigning to this.events is something Vue can notice.
Problem is solved. The issue didn't come from Vue but rather from the dhtmlx scheduler which wasn't parsing events when events was updated.
I ended up watching for any changes to events and thus, parsing it when it updates.
Thanks again for the help provided.
App.vue :
<template>
<div id="app">
<div class="container">
<scheduler v-bind:events="events"></scheduler>
</div>
</div>
</template>
<script>
import Scheduler from './components/Scheduler.vue';
import auth from './components/auth/index'
import data from './components/data/index'
import 'dhtmlx-scheduler'
export default {
name: 'app',
components: {
Scheduler
},
data() {
return {
events: []
}
},
created() {
this.getEvents();
},
watch: {
events: function(value) {
scheduler.parse(this.events, 'json');
}
},
methods: {
async getEvents() {
const token = await auth.getToken(this);
const apiToken = await auth.getApiToken(this, token);
this.events = await data.getApiData(this, apiToken, '/calendar/events', 307310564, this.events);
}
},
}
</script>