Accessing x-data in a function - alpine.js

I have the following code:
<div class="filter" x-data="filterData()">
<button #click="test()>Click me</button>
</div>
Filter Data
window.filterData = () => {
return {
section: null,
options: {
"one": [],
"two": [],
"three": []
},
test() {
console.log(this.options);
},
}
}
When I click on test() all I get back is Proxy {} in the console log. What can I do to actually interact with the options data?

The Proxy is the reactive wrapper used by Alpine to track updates but it functions the same as the wrapped value.
In this case if you do this.options.one.length you'll get 0.
If you need to inspect the value you can JSON.stringify() it

Related

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

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

Laravel vue.js and vuex link body text by id and show in a new component

I am very new to Laravel and Vuex, I have a simple array of post on my page.
test 1
test 2
test 3
I am trying to link the text on the AppPost.vue component and show the post that has been clicked on a new component (AppShowpost.vue) on the same page. I believe I have to get the post by id and change the state? any help would be good. Thank you.
when you click test 1 it will show "test 1" on a new component (AppShowpost.vue)
In side my store timeline.js, I belive I need to get the post by id and change the state ?
import axios from 'axios'
export default {
namespaced: true,
state: {
posts: []
},
getters: {
posts (state) {
return state.posts
}
},
mutations: {
PUSH_POSTS (state, data) {
state.posts.push(...data)
}
},
actions: {
async getPosts ({ commit }) {
let response = await axios.get('timeline')
commit('PUSH_POSTS', response.data.data)
}
}
}
My AppTimeline.vue component
<template>
<div>
<app-post
v-for="post in posts"
:key="post.id"
:post="post"
/>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
export default {
computed: {
...mapGetters({
posts: 'timeline/posts'
})
},
methods: {
...mapActions({
getPosts: 'timeline/getPosts'
})
},
mounted () {
this.getPosts()
}
}
</script>
My AppPost.vue component. I need to link the post.body to display the post in my AppShowpost.vue component.
<template>
<div class="w-full inline-block p-4">
<div class="flex w-full">
<p>
{{ post.body }}
</p>
</div>
</div>
</template>
<script>
export default {
props: {
post: {
required: true,
type: Object
}
}
}
</script>
My AppSowpost.vue component that needs to display the post that is clicked.
<template>
<div>
// Displaypost ?
</div>
</template>
<script>
export default {
// Get post from id ?
}
</script>
Okay you can create a new state in your vuex "current_state", asyou said, you can dispatch a mutation by passing the id to the vuex.
state: {
posts: [],
current_state_id : null
},
In your mutations
set_state_id (state, data) {
state.current_state_id = data;
}
On your app post.vue, you can set a computed property that watches the current state
computed: {
currentState() {
return this.$store.getters["timeline/current_state_id"];
}}
And create a watcher for the computed property to display the current id/post
watch: {
currentState: function(val) {
console.log(val);
},
Maybe this will help you. First I will recommend to use router-link. Read about router link here if your interested. It is very helpful and easy to use. But you will have to define the url and pass parameter on our vue-route(see bellow).
1.You can wrap your post.body in router-link as follow.
//With this approach, you don't need any function in methods
<router-link :to="'/posts/show/' + post.id">
{{ post.body }}
</router-link>
2. In your AppSowpost.vue component, you can find the post in vuex state based on url params as follow.
<template>
<div> {{ thisPost.body }} </div>
</template>
// ****************
computed: {
...mapState({ posts: state=>state.posts }),
// Let's get our single post with the help of url parameter passed on our url
thisPost() { return this.posts.find(p => p.id == this.$route.params.id) || {}; }
},
mounted() { this.$store.dispatch("getPosts");}
3. Let's define our vue route.
path: "posts/show/:id",
name: "showpost",
params: true, // Make sure the params is set to true
component: () => import("#/Components/AppShowPost.vue"),
Your Mutations should look as simple as this.
mutations: {
PUSH_POSTS (state, data) {
state.posts = data;
}
},
Please let me know how it goes.

Vee-validate: how use validate props callback

I'm using vee-validate to validate an input. The validation is custom, as if the input is not valid, a modal is shown and the input value is reset.
I've managed to implement this logic, calling this.$refs.provider.validate(value) inside the handler of #change input event.
However, I've also tried to use the "validate" props callback provided by the ValidationProvider but alas without success. It would be possible to use that for a logic like the one I've described?
My current code:
<template>
<div>
<ValidationProvider
:rules="rules"
v-slot="{ errors, valid }"
ref="provider"
:name="name"
slim
>
<b-form-input
ref="inputField"
:value="inputValue"
:key="inputKey"
#change="changeInput"
v-bind="$attrs"
:placeholder="name"
:state="errors[0] ? false : valid ? true : null"
lazy
type="number"
/>
</ValidationProvider>
<div>
<b-modal hide-header ok-only :id="modalId">
Modal body
</b-modal>
</div>
</div>
</template>
<script>
import { ValidationProvider } from "vee-validate";
export default {
components: {
ValidationProvider,
},
props: {
inputIndex: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
rules: {
type: [String, Object],
default: "",
},
},
data() {
return {
inputKey: 0,
modalId: "modal" + this.inputIndex,
};
},
computed: {
inputValue: function () {
return this.$store.getters["form/getMisuraN"](this.inputIndex);
},
},
watch: {},
methods: {
changeInput: async function (value) {
await this.updateinput(value);
//other logic not relevant to the issue
},
async updateinput(value) {
const { valid } = await this.$refs.provider.validate(value);
if (!valid) {
value = "";
this.$bvModal.show(this.modalId);
}
this.$store.dispatch("setInputValue", {
index: this.inputIndex,
value: value,
});
this.inputKey++;
},
},
};
</script>
What I'd like to do:
<template>
<div>
<ValidationProvider
:rules="rules"
v-slot="{ errors, valid, validate }"
ref="provider"
:name="name"
slim
>
[...]
</template>
<script>
[...]
methods: {
// use the validate function instead of calling this.$refs.provider.validate(value) inside the // #change handler method
}
</script>
You can!
Get the validate out of the slot for the VP, and pass it to your changeInput event:
<ValidationProvider
:rules="rules"
v-slot="{ errors, valid, validate }"
ref="provider"
:name="name"
slim
>
<b-form-input
ref="inputField"
:value="inputValue"
:key="inputKey"
#change="changeInput($event,validate)"
v-bind="$attrs"
:placeholder="name"
:state="errors[0] ? false : valid ? true : null"
lazy
type="number"
/>
</ValidationProvider>
Then in your changeInput function you'd do something like this:
changeInput: async function (value,validate) {
await this.updateinput(value,validate);
//other logic not relevant to the issue
},
async updateinput(value,validate) {
const { valid } = await validate(value);
if (!valid) {
value = "";
this.$bvModal.show(this.modalId);
}
/...
}

put vue variable with mounted on section('title')

i have problem with showing vue variable on blade template
my layouts/master.blade.php
<html>
<head>
<title>#yield('title') | My company</title>
.....
news.blade.php
#extends('layouts.master')
<div id="pagetitle">
#section('title', #{{pagetitle}} )
</div>
#section('content')
....
#endsection
resources/js/news.js
new Vue({
el: '#pagetitle',
data: {
pagetitle:'',
},
mounted() {
this.fetchArticlesPage();
},
methods: {
fetchArticlesPage(page_url) {
page_url = '/api/articles/news';
fetch(page_url)
.then(res => res.json())
.then(res => this.pagetitle = res.page_title)
.catch(err => console.log(err));
},
}
});
and this response data from controller with jsonResource
{
"links": {
"first": "http://localhost:8000/api/articles/news?page=1",
"last": "http://localhost:8000/api/articles/news?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "http://localhost:8000/api/articles/news",
"per_page": 3,
"to": 3,
"total": 3
},
"page_title": "News"
}
i got syntax error unexpected {
if i put on #section('content') like this
#section('content')
<div id="pagetitle">
#{{pagetitle}}
</div>
#stop
it' fine and will show the data which is "News",
please help, am new in vue and laravel programing
The Blade template directives are processed in the server and a response sent to the client.
After this, Vue template directives are processed in the browser.
On that account, the later example with the escaped Vue mustache works as expected as the block below is sent to the browser as a part of the overall response content.
<div id="pagetitle">
{{pagetitle}}
</div>
The Vue program running in the browser then runs, and interpolates variables in this template.
For the former example,
#section('title', #{{pagetitle}})
will result in an error in the server when it tries to compile the section as the second parameter is not given as a string.
This error can be corrected by quoting the escaped Vue mustache.
#section('title', '#{{pagetitle}}')
EDIT: {{pagetitle}} is not compiled is in document head
The Vue instance that is created is mounted on an element contained in the body. For this reason, compilation happens only on the document tree of the element that the Vue instance is mounted on.
I suggest to create a separate Vue instance to manage the head of the document. e.g.
const helmet = new Vue({
el: 'head',
data: {
pagetitle:'',
},
mounted() {
this.fetchArticlesPage();
},
methods: {
fetchArticlesPage(page_url) {
page_url = '/api/articles/news';
fetch(page_url)
.then(res => res.json())
.then(res => this.pagetitle = res.page_title)
.catch(err => console.log(err));
},
}
})
u can try this
#section('title', #pagetitle)

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