how to use Directus with gatsby - php

How is it possible to use the Directus data in getsby.js
I've setup a Directus app, and added tables and data/columns but I have no clue how to use it in gatsby.js, I have build a template like this in jsx:
const path = require('path')
exports.createPages = ({ boundActionCreators, graphql }, { urlPrefix }) => {
const { createPage } = boundActionCreators
return new Promise((resolve, reject) => {
resolve(
graphql(
`
{
allDirectusPost {
edges {
node {
id
title
author
content
}
}
}
}
`
).then(result => {
if (result.errors) {
console.error('GraphQL query returned errors')
reject(result.errors)
}
result.data.allDirectusPost.edges.forEach(edge => {
try {
let node = edge.node
let path = `posts/${node.id}`
createPage({
path,
layout: 'index',
component: path.resolve('src/templates/post.jsx'),
context: {
post: node,
},
})
console.log(`Generated page '${path}'`)
}
catch (error) {
console.error(`Failed to generate page posts/'${path}': ${error}`)
}
})
})
)
})
}
and I have a homepage static site in gatsby.js like this
import React from 'react'
import Link from 'gatsby-link'
// import postsTemplate from '../templates/post.jsx'
const IndexPage = () => (
<div>
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.000</p>
<p>Now go build something great.</p>
<post />
<Link to="/page-2/">Go to page 2</Link>
</div>
)
export default IndexPage
how do I call the directus data in that gatsby file?

For each item in your Directus table, a new page will be created based off the src/templates/post.jsx component. This will be a completely separate set of pages to the IndexPage.
The steps to source pages from Directus is very similar to the steps to source pages from Markdown. I recommend you read https://www.gatsbyjs.org/docs/adding-markdown-pages/ one more time (though it looks like you did read it, since your gatsby-node.js code looks like it was borrowed from there). In posts.jsx, instead of querying markdownRemark(frontmatter: { path: { eq: $path } }) you want to query allDirectusPost(edges: { node: {id: {eq: $path } } }).

Related

Vuex Laravel Loads all data

I've been trying to load all of my data when the time I log in. Currently, I've only managed to display data through the console through vuex file. I just want to achieve this because wherever it loads all data when login, it will easier for me to call every function on every page.
I think the first step is to display it on vue devtools?
This is what I've tried.
I have this file on my "./store/modules/currentUser.js"
import axios from "axios";
const state = {
};
const getters = {};
const actions = {
loadEmployee({}){
axios.post(BASE_URL + '/transportation/driver/autoComplete').then(response => {
console.log(response.data); // how to pass result to devtools?
});
}
};
const mutations = {};
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Login.vue
<script>
export default {
data () {
return {
listdata:[]
}
},
methods: {
login() {
this.$store.dispatch('currentUser/loadEmployee', this.listdata);
}
}
}
</script>
This is my vuedevtools looks like
And I want to fetch all data on listdata array vue devtools
If you are using vuex, you should probably load state in dev tools.
However, your issue is caused by not having a mutation, so you never update the state.
import axios from "axios";
const state = {
transansportDrivers: []
};
const getters = {};
const actions = {
loadEmployee({}){
axios.post(BASE_URL + '/transportation/driver/autoComplete').then(response => {
commit('setTransportDrivers', response.data)
});
}
};
const mutations = {
setTransportDrivers: (state, drivers) => {
state.transansportDrivers= drivers;
},
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
}

I'm using node/webpack with Wordpress

......and I've no idea what the hell I'm doing. 😬
Okay let me explain I'm going back over a Wordpress course I did on Udemy where the now AWOL instructor implemented a automated workflow for us to use whereby anytime we typed PHP or JS the webpage would reload automatically, and it's working, actually it's working too fast for me. This time round for some reason it's driving me bonkers cos when I'm writing my code the page is recompiled before I can even finish typing a complete line of code! The webpage generates a parse error and I have to manually refresh the page when I'm done to clear the error as it doesn't get automatically refreshed due to the error, which sort of defeats the purpose of the automation.
The automated workflow was basically implemented by doing the following:
I've installed 2 files package.json & webpack.config.js into my theme
folder
Then I ran npm run devFast
Then by changing functions.php we got the WP theme to use the Node
generated assets. Node serves up all of the JavaScript and CSS within
one single bundled file, bundled.js
I've no idea where to start in asking for help with this so thought I'd start here. As I say any help with this would be appreciated even if you just signpost me. I'm also using Local by Flywheel to host the site locally and this has been a great tool.
If it helps my webpack file is ...
/*
SUPER IMPORTANT: This config assumes your theme folder is named
exactly 'fictional-university-theme' and that you have a folder
inside it named 'bundled-assets' - If you'd like to adapt this
config to work with your own custom folder structure and names
be sure to adjust the publicPath value on line #116. You do NOT
need to update any of the other publicPath settings in this file,
only the one on line #116.
*/
const currentTask = process.env.npm_lifecycle_event
const path = require("path")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const ManifestPlugin = require("webpack-manifest-plugin")
const fse = require("fs-extra")
const postCSSPlugins = [require("postcss-import"), require("postcss-mixins"), require("postcss-simple-vars"), require("postcss-nested"), require("postcss-hexrgba"), require("postcss-color-function"), require("autoprefixer")]
class RunAfterCompile {
apply(compiler) {
compiler.hooks.done.tap("Update functions.php", function () {
// update functions php here
const manifest = fse.readJsonSync("./bundled-assets/manifest.json")
fse.readFile("./functions.php", "utf8", function (err, data) {
if (err) {
console.log(err)
}
const scriptsRegEx = new RegExp("/bundled-assets/scripts.+?'", "g")
const vendorsRegEx = new RegExp("/bundled-assets/vendors.+?'", "g")
const cssRegEx = new RegExp("/bundled-assets/styles.+?'", "g")
let result = data.replace(scriptsRegEx, `/bundled-assets/${manifest["scripts.js"]}'`).replace(vendorsRegEx, `/bundled-assets/${manifest["vendors~scripts.js"]}'`).replace(cssRegEx, `/bundled-assets/${manifest["scripts.css"]}'`)
fse.writeFile("./functions.php", result, "utf8", function (err) {
if (err) return console.log(err)
})
})
})
}
}
let cssConfig = {
test: /\.css$/i,
use: ["css-loader?url=false", { loader: "postcss-loader", options: { plugins: postCSSPlugins } }]
}
let config = {
entry: {
scripts: "./js/scripts.js"
},
plugins: [],
module: {
rules: [
cssConfig,
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-react", ["#babel/preset-env", { targets: { node: "12" } }]]
}
}
}
]
}
}
if (currentTask == "devFast") {
config.devtool = "source-map"
cssConfig.use.unshift("style-loader")
config.output = {
filename: "bundled.js",
publicPath: "http://localhost:3000/"
}
config.devServer = {
before: function (app, server) {
/*
If you want the browser to also perform a traditional refresh
after a save to a JS file you can modify the line directly
below this comment to look like this instead. I'm using this approach
instead of just disabling Hot Module Replacement beacuse this way our
CSS updates can still happen immediately without a page refresh.
If you're using a slower computer and the new bundle is not ready
by the time this is reloading the browser you can always just set the
"hot" property a few lines below this to false instead of true. That
will work on all computers and the only trade off is the browser will
perform a traditional refresh even for CSS changes as well.
*/
// server._watch(["./**/*.php", "./**/*.js"])
server._watch(["./**/*.php", "!./functions.php"])
},
public: "http://localhost:3000",
publicPath: "http://localhost:3000/",
disableHostCheck: true,
contentBase: path.join(__dirname),
contentBasePublicPath: "http://localhost:3000/",
hot: true,
port: 3000,
headers: {
"Access-Control-Allow-Origin": "*"
}
}
config.mode = "development"
}
if (currentTask == "build" || currentTask == "buildWatch") {
cssConfig.use.unshift(MiniCssExtractPlugin.loader)
postCSSPlugins.push(require("cssnano"))
config.output = {
publicPath: "/wp-content/themes/fictional-university-theme/bundled-assets/",
filename: "[name].[chunkhash].js",
chunkFilename: "[name].[chunkhash].js",
path: path.resolve(__dirname, "bundled-assets")
}
config.mode = "production"
config.optimization = {
splitChunks: { chunks: "all" }
}
config.plugins.push(new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: "styles.[chunkhash].css" }), new ManifestPlugin({ publicPath: "" }), new RunAfterCompile())
}
module.exports = config
As already posted:
I should have said I'm using the auto-save feature in VS Code and to save my sanity I've turned this off which is doing the job. But is there another or better way?

use dynamic params for axios requests

axios.get("/api/session/" + this.roomId)
Above is a snippet from my axios call that uses my api.php route ('/api/session/{id} that loads through the controller the requested specific room => /api/session/3 is room 3).
Currently, this snippet is harcoded and always uses integer 1 for 'this.roomId'.
I did that, in oder to check if my vue is even working fine.
My question is now, how am I able to use a dynamic param for my prop roomId?
so I can always say something like
.get/.post('url', $id) ?
If you're passing the roomId as a prop into the component then you need to handle the change in the parent component. For that I'd need a bit more context on where the room-ids come from and how you select the room-id there.
If you have this part down, then you'll want to watch changes on the roomId prop and re-fetch the data when ever it changes. You can do something like this in your room component:
<script>
import axios from 'axios'
const props: {
roomId: {
type: Number,
required: true
}
}
export default {
props,
data() {
return {
room: null
}
},
methods: {
async fetchRoom() {
try {
const response = await axios.get(`/api/session/${this.roomId}`)
this.room = response.data
} catch (err) {
// - handle error
}
}
},
watch: {
roomId: {
immediate: true // so it's executed when component is created
handler: function () {
this.fetchRoom()
}
}
}
}
</script>

bind remote data from php laravel into angular front-end

I just started building my backend in PHP laravel. What I'm doing is receiving data from a service and I'm trying to display it inside the view but errors.
dataservice.ts
getData() {
const headers = this.getHeaders();
const list = this.http.post('tespapi/data', {
pageSize: 10,
page: 1
},{headers});
return list.pipe(tap(_ => {
}));
}
Component
ngOnInit() {
this.callServices.testCall().subscribe( data => {
this.userList = data.result.data;
});
DATA Structure from Service
{"status":"ok","code":200,"message":"Names retrieved successfully","result":{"current_page":1,"data":[{"id":32,"fullname":"Larson King","description":null,"category":{"id":12,"name":"Purple"},"unit":{"id":12,"name":"group"},"status":{"id":2,"name":"maximum level"}}],"first_page_url":"http://sample.apitest/view?page=1","from":1,"last_page":3,"last_page_url":"http://http://sample.apitest/view?page=3","next_page_url":"http://sample.apitest/view?page=2","path":"http://sample.apitest/view","per_page":1,"prev_page_url":null,"to":1,"total":3}}
The data needed want is found in result.data
When I do data.result.data an error displays Property 'result' does not exist on type 'Object'
HTML
<div *ngFor="let item of userList">
{{item.fullname}} - {{item.descripition}}
</div>
You can do it as below.
ngOnInit() {
this.callServices.testCall().subscribe( (data: any) => {
this.userList = data.result.data;
});
}

How to pass Laravel data into Vue root instance with Laravel Mix Setup

So I am using Laravel 5.5. I have a data coming from my Controller and I want to pass it to my root vue instance not the component.
So for example I have the Dashboard Controller which has a data of "users"
class DashboardController extends Controller {
public function index(){
$user = User::find(1);
return view('index', compact('user'));
}
}
I am using Larave mix on my project setup. So my main js file is the app.js. That "$user" data I need to pass on the root Vue instance. Which is located in app.js
const app = new Vue({
el: '#dashboard',
data: {
// I want all the data from my controller in here.
},
});
If you don't want to use an API call to get data (using axios or else), you could simply try this :
JavaScript::put(['user' => $user ]);
This will, by default, bind your JavaScript variables to a "footer" view. You should load your app.js after this footer view (or modify param bind_js_vars_to_this_view).
In app.js :
data: {
user: user
}
Read more : https://github.com/laracasts/PHP-Vars-To-Js-Transformer
I would make a request to fetch the user's data as has been suggested.
Alternatively, you can add a prop to the dashboard component in index.blade.php and set the user like <dashboard :user="{{ $user }}"></dashboard>. You'll probably want to json_encode or ->toArray() the $user variable.
Then within the dashboard component you can set data values based on the prop.
props: ['user'],
data () {
return {
user: this.user
}
}
I just solved this by placing a reference on the window Object in the <head> of my layout file, and then picking that reference up with a mixin that can be injected into any component.
TLDR SOLUTION
.env
GEODATA_URL="https://geo.some-domain.com"
config/geodata.php
<?php
return [
'url' => env('GEODATA_URL')
];
resources/views/layouts/root.blade.php
<head>
<script>
window.geodataUrl = "{{ config('geodata.url') }}";
</script>
</head>
resources/js/components/mixins/geodataUrl.js
const geodataUrl = {
data() {
return {
geodataUrl: window.geodataUrl,
};
},
};
export default geodataUrl;
usage
<template>
<div>
<a :href="geodataUrl">YOLO</a>
</div>
</template>
<script>
import geodataUrl from '../mixins/geodataUrl';
export default {
name: 'v-foo',
mixins: [geodataUrl],
data() {
return {};
},
computed: {},
methods: {},
};
</script>
END TLDR SOLUTION
If you want, you can use a global mixin instead by adding this to your app.js entrypoint:
Vue.mixin({
data() {
return {
geodataUrl: window.geodataUrl,
};
},
});
I would not recommend using this pattern, however, for any sensitive data because it is sitting on the window Object.
I like this solution because it doesn't use any extra libraries, and the chain of code is very clear. It passes the grep test, in that you can search your code for "window.geodataUrl" and see everything you need to understand how and why the code is working.
That consideration is important if the code may live for a long time and another developer may come across it.
However, JavaScript::put([]) is in my opinion, a decent utility that can be worth having, but in the past I have disliked how it can be extremely difficult to debug if a problem happens, because you cannot see where in the codebase the data comes from.
Imagine you have some Vue code that is consuming window.chartData that came from JavaScript::put([ 'chartData' => $user->chartStuff ]). Depending on the number of references to chartData in your code base, it could take you a very long time to discover which PHP file was responsible for making window.chartData work, especially if you didn't write that code and the next person has no idea JavaScript::put() is being used.
In that case, I recommend putting a comment in the code like:
/* data comes from poop.php via JavaScript::put */
Then the person can search the code for "JavaScript::put" and quickly find it. Keep in mind "the person" could be yourself in 6 months after you forget the implementation details.
It is always a good idea to use Vue component prop declarations like this:
props: {
chartData: {
type: Array,
required: true,
},
},
My point is, if you use JavaScript::put(), then Vue cannot detect as easily if the component fails to receive the data. Vue must assume the data is there on the window Object at the moment in time it refers to it. Your best bet may be to instead create a GET endpoint and make a fetch call in your created/mounted lifecycle method.
I think it is important to have an explicit contract between Laravel and Vue when it comes to getting/setting data.
In the interest of helping you as much as possible by giving you options, here is an example of making a fetch call using ES6 syntax sugar:
routes/web.php
Route::get('/charts/{user}/coolchart', 'UserController#getChart')->name('user.chart');
app/Http/Controllers/UserController.php
public function getChart(Request $request, User $user)
{
// do stuff
$data = $user->chart;
return response()->json([
'chartData' => $data,
]);
}
Anywhere in Vue, especially a created lifecycle method:
created() {
this.handleGetChart();
},
methods: {
async handleGetChart() {
try {
this.state = LOADING;
const { data } = await axios.get(`/charts/${this.user.id}/coolchart`);
if (typeof data !== 'object') {
throw new Error(`Unexpected server response. Expected object, got: ${data}`);
}
this.chartData = data.chartData;
this.state = DATA_LOADED;
} catch (err) {
this.state = DATA_FAILED;
throw new Error(`Problem getting chart data: ${err}`);
}
},
},
That example assumes your Vue component is a Mealy finite state machine, whereby the component can only be in one state at any given time, but it can freely switch between states.
I'd recommend using such states as computed props:
computed: {
isLoading() { return (this.state === LOADING); },
isDataLoaded() { return (this.state === DATA_LOADED); },
isDataFailed() { return (this.state === DATA_FAILED); },
},
With markup such as:
<div v-show="isLoading">Loading...</div>
<v-baller-chart v-if="isDataLoaded" :data="chartData"></v-baller-chart>
<button v-show="isDataFailed" type="button" #click="handleGetChart">TRY AGAIN</button>

Categories