Alpinejs x-if is not being triggered - alpine.js

I have data that I am pulling from ajax. And I want this data display only when it is successfully pulled.
import Alpine from 'alpinejs'
import axios from 'axios'
const http = axios.create({
baseURL: 'url',
})
window.axios = http
window.Alpine = Alpine
document.addEventListener('alpine:init', () => {
Alpine.data('cart', () => ({
items: null,
init(){
window.axios.get('wc/store/cart')
.then(({data})=>{
this.items = data
console.log(this.items)
}).catch(error => {
console.log(error.toString())
})
},
}))
})
Alpine.start()
Now I am using this in my template
<div x-data="cart">
<template x-if="items">
<h1>Shopping Cart</h1>
<!-- display items here -->
</template
</div>
The thing is, the h1 element is displayed but not the data from ajax.
Am I doing anything wrong. I am pretty confidence this should work.

You're not displaying your items. Keep in mind that template tags require a single root element only.
<div x-data="card">
<template x-if="items">
<div>
<h1>Shopping Cart</h1>
<template x-for="item in items">
<div>
<h2 x-text="item.text"></h2>
</div>
</template>
</div>
</template>
</div>

Related

How to plug existing Observables into Alpine.js (liveQuery from Dexie.js)

How are existing reactive observables connected to Alpine.js?
The Dexie.js website lists a few examples with React and Svelte but how would I use Dexie.js liveQuery with Alpine.js? Is it as simple as passing the variable to x-data?
You cannot pass directly a liveQuery object to an Alpine.js property because it will lose reactivity. We need to create a small wrapper that updates Alpine.js data when a liveQuery returns new data. Here I provide a small example that uses a products table, the Alpine.js component just lists the products and there's a small form that can add new products to the DB.
Example database definition in db.js:
import Dexie from 'dexie'
export const db = new Dexie('myDatabase')
db.version(1).stores({
products: '++id, name, color',
})
In main.js we make db and liveQuery global:
import Alpine from 'alpinejs'
import { liveQuery } from "dexie"
window.liveQuery = liveQuery
import { db } from './db'
window.db = db
window.Alpine = Alpine
window.Alpine.start()
The example Alpine.js component:
<div x-data="productsComponent">
<div>
<input type="text" x-model="name" placeholder="Name" />
<input type="text" x-model="color" placeholder="Color" />
<button #click="add">Add product</button>
</div>
<div>
<h2>Products</h2>
<template x-for="p in products">
<div x-text="`ID: ${p.id} Name: ${p.name} Color: ${p.color}`"></div>
</template>
</div>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('productsComponent', () => ({
products: [],
name: '',
color: '',
observe(dataName, observable) {
const subscription = observable.subscribe({
next: val => {this[dataName] = val}
})
},
init() {
this.observe('products', liveQuery(() => db.products.toArray()))
},
async add() {
const id = await db.products.add({
name: this.name,
color: this.color,
})
this.name = ''
this.color = ''
}
}))
})
</script>
In the observe method we subscribe the specific liveQuery event and update the Alpine.js data when it changes.

Laravel Sanctum Breeze with Next JS

I just installed this https://github.com/laravel/breeze-next repository and as expected everything works fine as documented. Login, Logout and registration work fine.
Now after login, I want to protect the API routes, but it throws errors as 401 when I try to access the protected route even after login.
Here is AXIOS setup as given in Repo,
import Axios from 'axios'
const axios = Axios.create({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
withCredentials: true,
})
export default axios
I just added a server call with Axios with \api\test
export async function getStaticProps() {
const response = await axios.get(`/api/test`);
return {
props: {
customers: response.data
},
}
}
This is API in laravel.
Route::middleware(['auth:sanctum'])->get('/test', function () {
return response()->json([
'val' => 1,
'msg' => 'successfully',
]);
});
If I remove middleware, it works fine. But when added middleware auth sanctum, it always shows 401 error.
Server Error
Error: Request failed with status code 401
This error happened while generating the page. Any console logs will be displayed in the terminal window.
So I can give authentication in SPA with sanctum?
Have you already added sanctum to your kernel.php?
By default \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,in your Kernel.php is commented out.
It should be look like that:
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
I was facing the same problem and instead using getStaticProps function I was able to resolve using useEffect() using the axios setup provinding by the repo, so you could try this way instead.
Assuming your directories structure pages/test.js, in your case would be:
import axios from "../lib/axios";
import {useEffect, useState} from "react";
import AppLayout from "../components/Layouts/AppLayout";
const Test = () => {
const [customers, setCustomers] = useState()
useEffect(() => {
axios
.get("/api/tests")
.then((response) => {
setCustomers(response.data);
})
.catch((error) => console.error(error));
}, []);
return (
<AppLayout
header='Customers'
>
<Head>
<title>Customers</title>
</Head>
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-slate-200">
{customers.map((customer, index) => (
<div key={customer.val}>
<div>
{customer.val}
{customer.message}
</div>
</div>
))}
</div>
</div>
</div>
</div>
</AppLayout>
)
}
And if you need to create a detail view with the same method within this directory structure test/[id].js:
import axios from "../../lib/axios";
import AppLayout from "../../components/Layouts/AppLayout";
import Head from "next/head";
import {useEffect, useState} from "react";
import {useRouter} from "next/router";
const Profiles = () => {
const [customer, setCustomer] = useState()
// Use router to get the id from the url your visiting
const router = useRouter();
useEffect(() => {
if(!router.isReady) return;
axios
.get(`/api/tests/${router.query.id}`) // Here we accessing the url parameter from useRouter()
.then((response) => {
setCustomer(response.data);
})
.catch((error) => console.error(error));
}, [router.isReady]);
return (
<AppLayout
header='Customer'
>
<Head>
<title>Customer</title>
</Head>
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-slate-200">
<div>
{customer.val}
{customer.message}
</div>
</div>
</div>
</div>
</div>
</AppLayout>
)
}
credits:
Use axios within useEffect How do I fix the 401 Unauthorized error with Laravel Sanctum and React?
Get url parameter from useRouter() https://github.com/vercel/next.js/discussions/12661#discussioncomment-360764

Unknown custom element: <app-home> - did you register the component correctly? For recursive components, make sure to provide the "name" option

I have this problem but i try some solutions in web but and i can't resolve it: Unknown custom element:
- did you register the component correctly? For recursive components, make sure to provide the "name" option.
The problem appears to be in those fils :
Please I need help as soon as possible
routes.js:
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../components/Home.vue";
import PostDetails from "../components/PostDetails.vue";
Vue.use(VueRouter);
const routes = [{
path: "/",
component: Home,
name: "Home"
},
{
path: "/post/:slug",
component: PostDetails,
name: "postDetails"
}
];
const router = new VueRouter({
routes: routes,
hashbang: false,
mode: "history"
});
export default router;
app.js:
import Vue from "vue";
import VueRouter from "vue-router";
require('./bootstrap');
window.Vue = require('vue');
Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('app-home', require('./AppHome.vue'));
import router from "./routes/routes.js";
const app = new Vue({
el: '#app',
vuetify,
render: h => h(App),
router: router,
});
AppHome.vue:
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
};
</script>
Home.vue:
<template>
<div class="container">
<div class="row my-4">
<div class="col-md-8">
<div class="card">
<div class="card-header">Articles</div>
<div
class="card-body"
:key="index"
v-for="(post, index) in posts.data"
>
<div class="media">
<img
:src="post.photo"
class="rounded img-fluid mr-2 shadow-sm"
alt=""
srcset=""
/>
<div class="media-body text-justify">
<router-link :to="post.path">
<h3>{{ index }}:{{ post.title }}</h3>
</router-link>
<p>
<span class="textdefaut">
{{ post.user.name }}
</span>
<span class="text-danger">
{{ post.added }}
</span>
</p>
<p class="lead text-justify">
{{ post.body.substr(0, 200) }}...
</p>
<hr />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
posts: {},
};
},
created() {
this.getPosts();
},
methods: {
getPosts() {
axios
.get("/api/posts")
.then((response) => {
console.log(response.data);
this.posts = response.data;
})
.catch((err) => console.log(err));
},
},
};
</script>
Post Details:
<template>
<div>
Posts details , This shows that the route is really working!!
<router-link to="/Home"><a>Back to the root</a></router-link>
</div>
</telpmate>
<script>
export default {
data () {
return {
message: 'Hoera!!!!'
};
}
};
</script>
If all of your Vuejs components (including AppHome.vue) are in /resources/js/components directory, you must change:
Vue.component('app-home', require('./AppHome.vue'));
by
Vue.component('app-home', require('./components/AppHome.vue'));
...in your app.js
Try to append .default option:
Vue.component('app-home', require('./components/AppHome.vue').default);

vue components wont load

I try to work with vuejs in laravel, I installed npm vue-router vue-axios but when i try to load my page i get console error like: ReferenceError: CreateCategory is not defined and empty page.
here is my app.js:
require('./bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);
import App from './App.vue';
Vue.component('CreateCategory', require('./components/CreateCategory.vue'));
Vue.component('DisplayCategory', require('./components/DisplayCategory.vue'));
Vue.component('EditCategory', require('./components/EditCategory.vue'));
const routes = [
{
name: 'CreateCategory',
path: '/categories/create',
component: CreateCategory
},
{
name: 'DisplayCategory',
path: '/',
component: DisplayCategory
},
{
name: 'EditCategory',
path: '/edit/:id',
component: EditCategory
}
];
const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');
// const app = new Vue({
// router,
// render: h => h(App)
// });
// const app = new Vue({
// el: '#app'
// });
PS: I read articles about component in router and I already tried with .default that won't work neither they only good of that was i didn't get console error.
UPDATE
my CreateCategory.vue component:
<template>
<div>
<h1>Create A Category</h1>
<form v-on:submit.prevent="addCategory">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Category Title:</label>
<input type="text" class="form-control" v-model="category.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Category Status:</label>
<input type="text" class="form-control col-md-6" v-model="category.status" />
</div>
</div>
</div><br />
<div class="form-group">
<button class="btn btn-primary">Add Category</button>
</div>
</form>
</div>
</template>
<script>
export default {
data(){
return{
category:{}
}
},
methods: {
addCategory(){
let uri = 'http://localhost/vuetjd/public/categories';
this.axios.post(uri, this.category).then((response) => {
this.$router.push({title: 'DisplayCategory'})
})
}
}
}
</script>
CreateCategory.vue is a Single File Component.
In there, you must have a export default {}, where {} is actually the Component Object.
What you have to do, is that, you need to import the CreateCategory.vue and then assign it, like so:
import CreateCategory from './components/CreateCategory.vue';
const routes = [
{
name: 'CreateCategory',
path: '/categories/create',
component: CreateCategory
}
];
now this will work.
you have to do the same for DisplayCategory and EditCategory.
I found what is the issue, I'm suppose to run php artisan serve to be able to see my data. if just open my url i'll get blanck page but with serve i get my data as well.

Vue Multiselect not displaying

I am trying to use Vue Multiselect V2 in my Laravel 5.3 project. I am using this example, http://monterail.github.io/vue-multiselect/#sub-single-select
I have the following setup, in my app.js file:
Vue.component('multiselect', require('./components/Multiselect.vue'));
var vm = new Vue({
el: '#app'
});
In the Multiselect.vue file
<script>
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
data () {
return {
value: '',
options: ['Select option', 'options', 'selected', 'mulitple', 'label', 'searchable', 'clearOnSelect', 'hideSelected', 'maxHeight', 'allowEmpty', 'showLabels', 'onChange', 'touched']
}
}
}
</script>
And I am calling it in the blade as below:
<div id="app">
<label class="typo__label">Single select</label>
<multiselect v-model="value" :options="options" :searchable="false" :close-on-select="false" :show-labels="false" placeholder="Pick a value"></multiselect>
<pre class="language-json"><code>#{{ value }}</code></pre>
</div>
This is how it displays in the DOM
<div id="app">
<label class="typo__label">Single select</label>
<!---->
<pre class="language-json"><code></code></pre>
</div>
Currently the dropdown does not display, and I don't see any errors in the console. I would have expected to add a template in somewhere but I couldn't find any mention of that in the Vue Multiselect docs.
For anyone having these issues, do not follow the examples on the official documentation. They do not work, rather use this from their Github page. https://github.com/monterail/vue-multiselect/tree/2.0#install--basic-usage
Basic example
<template>
<div>
<multiselect
v-model="selected"
:options="options">
</multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
components: { Multiselect },
data () {
return {
selected: null,
options: ['list', 'of', 'options']
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
For updating the array from vue multiselect use #select and #remove events
Example: <multiselect #select="selectionChange" #remove="removeElement"> </multiselect>
Into methods add the next functions
methods: {
removeElement() {
this.$forceUpdate();
},
selectionChange() {
this.$forceUpdate();
},
}
this.$forceUpdate(); will update the state.

Resources