AlpineJS pass an array from php to x-init - javascript

I am currently working on a project that involves utilizing PHP and MySQL for data retrieval, and Alpine.js for dynamic front-end interactions. My goal is to pass the array returned from my data fetch in MySQL to the x-init function in Alpine.js, as I am relatively new to using this JavaScript framework. I would like to include what I have accomplished so far:
data.php
<?php
function dbConn() {
// some database connection here using PDO...
}
function getPosts() {
return db()->query('SELECT u.username,p.* FROM users u JOIN posts p on u.id = p.user_id')->fetchAll(PDO::FETCH_ASSOC);
}
index.php
<?php
$results = getPosts();
print("<pre>".print_r($results,true)."</pre>");
?>
<div x-data="posting()" x-init="fetchPost(<?php json_encode($results); ?>)">
<template x-for="post in posts" :key="post.id">
<h2 x-text="post.title"></h2>
<p x-text="post.content"></p>
</template>
</div>
app.js
document.addEventListener("alpine:init", () => {
Alpine.data("posting", () => ({
fetchPost: (data) => {
this.posts = data;
console.log(this.posts);
},
posts: [],
}));
});
Here is the result on my console and above is my array structure:
thank you in advance!

You almost got it right. You forgot to use echo.
<div x-data="posting()" x-init="fetchPost(<?php echo htmlspecialchars(json_encode($results), ENT_QUOTES, 'UTF-8', true) ?>)">

Related

How to pass JavaScript variables to Laravel route parameter

How can I pass JavaScript variables to Laravel route?
This is my route
Route::get('user/checkout/id={id}&subscription_id={subscription_id}&access_token={access_token}', [CheckoutController::class, 'checkout_after'])->name('user.checkout_after');
This is my js, but the problem is I get undifined variable error for the subscription_id. Other 2 parameters ok.
onApprove: function(data, actions) {
<?php echo $subscription_id ?> = data.subscriptionID;
window.location.href = "{{ route('user.checkout_after', ['id' => $plan->id, 'subscription_id' => $subscription_id, 'access_token' => $access_token]) }}";
}

Laravel 5: show comments using Vue.js

I am creating blog commenting system, I want to show comments for a post using vue.js.
In console, it says
Property or method "comment" is not defined on the instance but
referenced during render.
Also, when I try to catch user name, I got this error
Error in render: "TypeError: Cannot read property 'user' of undefined"
I want to show comments and users who commented to a particular post
in show.blade.php.
web.php
Route::get('results/{post}', 'ResultsController#show')->name('posts.show');
ResultsController
public function show(Post $post)
{
$recommended_posts = Post::latest()
->whereDate('date','>',date('Y-m-d'))
->where('category_id','=',$post->category_id)
->where('id','!=',$post->id)
->limit(7)
->get();
$posts['particular_post'] = $post;
$posts['recommended_posts'] = $recommended_posts;
//return $post->comments()->paginate(5); it returns objects
return view('posts.show',compact('posts'));
}
Comments.vue
<div class="reply-comment" :v-for="comment in comments">
<div class="user-comment" >
<div class="user">
<!--<img src="" alt="" >-->
<avatar :username="comment.user.name" :size="30" ></avatar>
</div>
<div class="user-name">
<span class="comment-name">{{ comment.user.name }}</span>
<p> {{ comment.body }} </p>
</div>
</div>
<div class="reply">
<div class="seemorecomments">
see more
</div>
<button class="reply-button">
<i class="fas fa-reply"></i>
</button>
</div>
</div>
<script>
import Avatar from 'vue-avatar'
export default {
props: ['post'],
components: {
Avatar
},
mounted() {
this.fetchComments()
},
data: () => ({
comments: {
data: []
}
}),
methods: {
fetchComments() {
axios.get(`/results/${this.post.id}`).then(({ data }) => {
this.comments = data
})
}
}
}
show.blade.php
<comments-component :post="{{ $posts['particular_post']->comments }}"></comments-component>
migration table
Schema::create('comments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id');
$table->integer('post_id');
$table->text('body');
$table->integer('comment_id')->nullable();
$table->timestamps();
});
comment.php, I have this.
protected $with = ['user'];
You have a couple of minor issues with your Vue file that can be addressed pretty quickly.
First, you should define comments as an empty array — a collection will be returned as an array of objects to the Vue. By adding an unnecessary data property in the beginning, you are allowing the v-for loop to run in your template before the data has been retrieved.
EDIT: I'm not sure about the way you wrote this data function, so I have re-written it a way in which I'm familiar.
data() {
return {
comments: []
}
},
Second, you want to get the correct data from the response. Axios data is stored another level deep (response.data). Of course, if you are paginating the results, they are one more level deep (response.data.data).
fetchComments() {
axios.get(`/results/${this.post.id}`).then(response => {
this.comments = response.data
// or for paginated results
// this.comments = response.data.data
})
}
EDIT: Thank you for providing the Gist! I think I'm seeing things more clearly now.
Update your controller like so:
You want to load the comments into the post here.
public function show(Post $post)
{
$recommended_posts = Post::latest()
->whereDate('date','>',date('Y-m-d'))
->where('category_id','=',$post->category_id)
->where('id','!=',$post->id)
->limit(7)
->get();
// load the post comments here
$post->load('comments');
$posts['particular_post'] = $post;
$posts['recommended_posts'] = $recommended_posts;
return view('posts.show',compact('posts'));
}
And you blade like so:
Your module wants a single post, not an array of comments.
<comments-component :post="{{ $posts['particular_post'] }}"></comments-component>
And you Vue like so:
You don't actually need to use Axios at all since we've already loaded the comments.
<script>
import Avatar from 'vue-avatar'
export default {
props: ['post'],
components: {
Avatar
},
data() {
return {
comments: this.post.comments
}
},
}
</script>

How am I meant to render different buttons based on a record in database when having a separated front & back end

I have a separated front and back end. The front-end is JavaScript with Vue.js and the back-end is PHP with Laravel. The authentication is token based.
I have created a functionality which allows a user to wishlist sights and in order to wishlist a sight, the user has to click a button. When the user wishlists a sight, a record is inserted into the database and I can determine if a user has wishlisted a place based on it. Now I am trying to change which button is rendered when the component is loaded based on the record inside the database.
<template>
<div>
<button #click='addTo("wishlistedPlaces")'>Remove from wishlist</button>
<button #click='addTo("wishlistedPlaces")'>Add to wishlist</button>
</div>
</template>
<script>
export default {
data(){
return {
placeId: this.$route.params.placeid,
sight: null
},
mounted() {
axios.get('/getSight/' + this.placeId)
.then(response => {
this.sight = response.data.result.result;
}).catch((error) => console.log(error));
}
</script>
The GET request on mounted executes this PHP function which just returns the sight information:
public function getSight(Request $request, $placeId) {
$get = file_get_contents("https://maps.googleapis.com/maps/api/place/details/json?placeid=" . $placeId . "&key=");
$result = json_decode($get);
return response()->json([
'result' => $result
], 201);
}
And this code, not yet implemented anywhere returns true or false based on whether the user has wishlisted a certain place or not:
$user = User::where('username', $username)->first();
$checkIfWishlisted = $user->wishlistedPlaces->contains(function ($place) use ($placeId) {
return $place->place_id == $placeId;
});
So my question is where exactly in the back-end should I check if the user has wishlisted a place so I could send the boolean response to the front-end and then how should I use that boolean in the front end?
Now I am trying to change which button is rendered when the component
is loaded based on the record inside the database.
One way would to create another data property to hold information about if the user has it on whishlist or not
data() {
return {
onWishlist: false
}
}
Under mounted make another axios call.
mounted() {
axios.get('/checkWishlist/' + this.placeId)
.then(response => {
this.onWishlist= response.data;
})
.catch((error) => console.log(error));
}
In the template make a v-if statement on the buttons
<button v-if="onWishlist" #click='addTo("wishlistedPlaces")'>Remove from wishlist</button>
<button v-if="!onWishlist" #click='addTo("wishlistedPlaces")'>Add to wishlist</button>
Working codepen: https://codepen.io/bergur/pen/EzEBWo

Axios get to php file using vuejs cli doesn't work

each time i make a get request to a php file using axios on the vuejs cli, it doesnt run the script, rather it dumps out the full php script without actually running the script.
But if i try accessing that address with the needed parameters from my browser's address bar, it returns the right response.
Here's my code: Vue Component making the get request
<script>
import axios from 'axios'
export default{
data(){
return{
id : this.$route.params.id,
post:{}
}
},
created(){
axios.get('../../php/ajaxfile.php?postid='+this.id).then((response)=>{
this.post = response.data;
console.log(response.data);
}).catch((error) =>{
console.log(error);
});
}
}
Php Script:
<?php
include 'config.php';
if(isset($_GET['postid'])){
$condition = " id=".$_GET['postid'];
}
$userData = mysqli_query($con,"select * from blogpost WHERE ".$condition );
$response = array();
while($row = mysqli_fetch_assoc($userData)){
$response[] = $row;
}
echo json_encode($response);
exit;
Please help me figure out what i'm doing wrong
If you are in dev environnement you probably access your vue app by http://localhost:8080.
Your axios should call real url of your local web server :
axios.get(process.env.ROOT_API+'/ajaxfile.php?postid='+this.id)
And add the ROOT_API definition to your dev and prod config (/config/dev.env.js and /config/prod.env.js) :
here is my dev.env.js :
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
ROOT_API: '"http://my-local-domaine.ltd"',
})

vue js ajax call cannot read property 'push' of undefined

I am having problems with vue.js when it comes to pushing data from the database to the webpage. I am using laravel 5.3 which converts data to Jason. the code posts to the server the number of records to be fetched then the server response with the data in which i want to display on the webpage. here is Vue js Code
new Vue({
el: "#projects",
data: {
count: 0,
fetched_projects: []
}
methods:{
checkproject: function(){
var fetch = this.count += 4;
axios.post('/loadmore', {fetch: fetch })
.then(function(response) {
this.fetched_projects.push(response.data);
})
.catch(function(error){
console.log(error);
});
}
HTML
<div class="row">
<div class="col-md-3">
<ul v-for="more_projects in fetched_projects">
<li>#{{ more_projects }}</li>
</ul>
</div>
</div>
Laravel controller
public function setloadMore(Request $request){
$new_projects = $request->fetch;
$results = Model1::with('relation')->take($new_projects)->get();
return $results;
}
The problem is on this.fetched_projects.push(response.data); its giving me "cannot read property 'push' of undifined"
You'd want this to be your component, so use an arrow function:
methods:{
checkproject: function(){
var fetch = this.count += 4;
axios.post('/loadmore', {fetch: fetch })
.then(response => {
this.fetched_projects.push(response.data);
})
.catch(function(error){
console.log(error);
});
}
you are having "this" problem, try defining something like var that = this where you have defined fetch, and use that in place of this inside the post it should work.

Categories