Laravel Nova | Arrow functions | computed property not working in Tool.vue - laravel

I have a computed property that is not working correctly. When reading the docs this is how it should be done for Vue 2.x. The code i have:
<template>
<div>
<button :disabled="isDisabled">Import configurator data</button>
<input class="input" type="file" id="file" v-on:change="setFile">
</div>
</template>
<script lang="js">
export default {
data: () => {
return {
importDisabled: true,
}
},
computed: {
isDisabled() {
return this.importDisabled;
},
},
methods: {
setFile: (e) => {
this.importDisabled = false;
},
}
}
</script>
Expected behaviour: Button enables when a file is selected.
Actual behaviour: Button stays disabled.
What am i missing here? A console.log within the isDisabled() methods shows it is only called once. It is not called after importDisabled changes.
Other info:
vue 2.6.12
laravel nova
Also note: Vue tools does not detect a Vue component in the inspector. But the Vue behaviour is working when loading the tool.

It seems arrow functions are bound to the parent context. That was the reason my code did not work. this is then not bound to the Vue instance but the parent (Window) which causes it not to work.
Wrong:
setFile: (e) => {
this.importDisabled = false;
},
Right:
setFile: function() {
this.importDisabled = false;
},
More information:
https://codingexplained.com/coding/front-end/vue-js/using-es6-arrow-functions-vue-js

Related

Vue - rendering templates after Ajax call

I have a page which loads some information chunks at the beginning and it loads other ones when user scroll down. In this chunks I have also , for which I have a function written.
Simplified structure of the chunk looks like that:
<div class="chunk_class">
<div class="chunk_header">
<div class="title"></div>
<div class="subtitle"></div>
</div>
....
<div class="actions">
<comparison-training-toggle training-id="70" init-comparison="0" icon="n-compare" class="v-comparison-toggle" title="Some title"></comparison-training-toggle>
<div class="another_action"></div>
</div>
It works for the chunks that I load at page load, but it doesn't work for the other ones that I load through Ajax call. How can I make it work also for Ajax loaded ones? Do I need to install some other modules (I have now installed Vue, Vue-resource & Vue-router)?
Below part of the function that I wrote with comments what does and what doesn't work:
$(document, context).once('vue__comparison_toggle_add').each(() => {
Drupal.behaviors.vue__comparison_toggle.vueComponent(); //this works
});
$(document).ajaxComplete(function(e, xhr, settings){
Drupal.behaviors.vue__comparison_toggle.vueComponent();//it enters the the ajaxComplete, but doesn't work, it still remains <comparison-training-toggle>...
});
},
vueComponent: function () {
Vue.component('comparison-training-toggle', {
template: this.template,
props: ['trainingId', 'icon', 'init-comparison'],
data() {
return {
inComparison: false,
}
},
computed: {
toggleText() {
return this.inComparison ? Drupal.t('Usuń z porównania') : Drupal.t('Dodaj do porównania')
}
},
methods: {
toggle() {
...

v-navigation-drawer controlled state from a sub-component

I have a v-navigation-drawer which can be opened by clicking a button in a sub component.
So I changed v-model="drawer" to simply value="drawer" otherwise I get a warning about mutating a prop which makes sense (feels like doing some dirty angular double-way data binding ^^).
Here's the code:
layouts/default.vue:
<template>
<Header :toggleLeftMenu="toggleLeftMenu" />
<LeftMenu :show="showLeftMenu" :toggleLeftMenu="toggleLeftMenu" />
</template>
<script>
export default {
data() {
return {
showLeftMenu: true,
}
},
methods: {
toggleLeftMenu() {
this.showLeftMenu = !this.showLeftMenu;
},
}
}
</script>
components/layout/LeftMenu.vue:
<v-navigation-drawer
:value="show"
width="300"
clipped
fixed
app
>
This issue is that the drawer can be closed by clicking on the backdrop (on small devices). I need to plug the backdrop click to toggleLeftMenu prop, but according to the doc, this doesn't seem to be possible.
How can I achieve full control on the component? Is this #backdropClick event missing or something?
I tried to use #input but it creates an infinite loop which also makes sense.
Thanks
Using vuetify 2.6.1.
I changed v-model="drawer" to simply value="drawer" otherwise I get a warning about mutating a prop
This is not quite the right decision. Of course you should not use drawer as model, but you can create an internalDrawer prop in LeftMenu component, and leave the v-model where it is.
One of the possible ways to resolve your issue is to emit events from both sub-components into its parent.
So let's rewrite your LeftMenu component this way:
<template>
<v-navigation-drawer v-model="internalShow" width="200" clipped fixed app>
some drawer data
</v-navigation-drawer>
</template>
<script>
export default {
props: {
show: Boolean,
},
data() {
return {
internalShow: this.show,
};
},
watch: {
show (val) {
this.internalShow = val;
},
internalShow (val) {
if (val !== this.show) {
this.$emit("change-drawer-state");
}
},
},
};
</script>
In this case, every time when the internalShow state changes, an change-drawer-state event will be emitted.
Your Header component can be rewrited the same way:
<template>
<v-btn #click="$emit('change-drawer-state')">Drawer button</v-btn>
</template>
And this is the code of your parent component:
<template>
<div>
<Header #change-drawer-state="toggleLeftMenu" />
<LeftMenu :show="showLeftMenu" #change-drawer-state="toggleLeftMenu" />
</div>
</template>
<script>
import LeftMenu from "./LeftMenu";
import Header from "./Header";
export default {
components: {
LeftMenu,
Header,
},
data() {
return {
showLeftMenu: false,
};
},
methods: {
toggleLeftMenu() {
this.showLeftMenu = !this.showLeftMenu;
},
},
};
</script>
Both change-drawer-state event handlers are calling the same method - toggleLeftMenu and then the method changes show prop of navigation-drawer.
You can test this solution in a CodeSandbox playground.

Call a Vue.js function inside app.blade.php on button click

Hy Guys,
I need to call a Vue.js function inside app.blade.php file. It should be triggered on a button click.
Here is the code sample I've used.
<button onclick="changeItem()">Saved Items</button>
changeItem() is a Vue.js function.
Kindly help :)
In your app.blade define the component
<div id="app">
<example-component></example-component>
</div>
By defualt laravel will include Vue JS packages in resources\js\app.js
In your resources\js\components\ExampleComponent.vue (Below Code)
<template>
<button v-on:click="say">Say what</button>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
},
// define methods under the `methods` object
methods: {
say: function (event) {
// `this` inside methods points to the Vue instance
alert('Hello ')
// `event` is the native DOM event
if (event) {
alert(event.target.tagName + " Clicked ")
}
}
}
}
</script>
Run : npm run watch // To compile app.js
Please mark/upvote if this finds helpful :)
<div id="app">
<button #click="changeItem">
{{message}}
</button>
</div>
new Vue({
data: {
message: "Save Items"
},
methods: {
changeItem() {
alert("Clicked!")
}
}
})
#click="changeItem" it is short form v-on:click="changeItem"
Please read this

Vuejs Displaying a component multiple times with Axios in it

I have been trying to figure out this for a hours but no luck. I have 2 components. The first component is dynamic and the second component just gets the user geolocation. The geolocation is then displayed in the first component.
My problem is that I display the first component a few times on the page and every time it is displayed it makes a GET request which is inefficient . If I display the component 3 times it will make 3 GET requests.
What would be the best way to rewrite this?
Thanks for the help
Component 1:
<template>
<section id="under-info">
THe user is from <ip_info></ip_info>
</section>
</template>
<script>
export default {
}
</script>
Component 2:
<template>
<span id="user-city">
{{value}}
</span>
</template>
<script>
export default {
mounted: function () {
this.$nextTick(function () {
this.getIpInfo(this.param)
})
},
props:['param'],
data: function () {
return {
value:null
}
},
methods:{
getIpInfo(){
var vm = this
delete axios.defaults.headers.common["X-Requested-With"];
delete axios.defaults.headers.common["X-CSRF-TOKEN"];
axios
.get('http://api.ipstack.com/check?access_key=?',{
timeout: 1000
})
.then(function(response) {
vm.value = response.data['city]
})
}
},
}
</script>
Wrap the code where you want to reuse this value 3x in a component.
<template>
<div>
The user is from {{location}}, and {{location}} is a great place. They have a baseball team in {{location}}
</div>
</template>
<script>
export default {
mounted: function () {
this.$nextTick(function () {
if(this.needLocation){
this.getIpInfo(this.param)
}
})
},
props:['param', 'needLocation'],
data: function () {
return {
location:null
}
},
methods:{
getIpInfo(){
this.location = //results from your API call
}
}
</script>

dusk test about continuity click(double click) without waiting backend process

I am testing the following due with laravel dusk.
Vue component purpose is disable continuity click by user to avoid registering duplicate data.
The test I want to implement is fast continuity click by user.
But after
$browser->assertSourceHas($buttonEnableSource)
->click('#submit-button-component')
Test will wait for browser process.
So if I write down the following, it will make error that has no applicable Vue.
$browser->assertSourceHas($buttonEnableSource)
->click('#submit-button-component')
->click('#submit-button-component')
Is there a way to implement fast continuity click by user with dusk?
The following is the source code.
<template>
<div>
<input type="submit" class="button_orange button_big" :value="value" v-show="!isSubmitting" #click="startSubmit">
<div class="button_white button_big" v-show="isSubmitting">{{ value }}</div>
</div>
</template>
<script>
export default {
data() {
return {
isSubmitting: false,
};
},
props: {
value: {
type: String,
default: '',
},
},
methods: {
startSubmit() {
this.isSubmitting = true;
},
},
};
</script>
public function testRegisterDoubleClickNoDuplication()
{
$this->browse(function (Browser $browser) {
$buttonValue = __('common.register');
$buttonEnableSource = "<input type=\"submit\" class=\"button_orange button_big\" value=\"{$buttonValue}\" />";
$browser->visit(route('staffs.create'))
->assertSourceHas($buttonEnableSource)
->click('#submit-button-component')
->assertSourceMissing($buttonEnableSource)
->assertSee('スタッフ詳細');
});
}

Resources