Laravel Nova - Custom Card w/ Package - laravel

I created a custom card in order to use Chartkick. This custom card will have a select dropdown which will make an Axios request to get data from an API and display it in the chart though my issue is the chart will not display even with hard-coded dummy data as can be seen below:
<template>
<card class="flex flex-col items-center justify-center">
<span>Ben</span>
<line-chart class="lcs" :data="chart_data"></line-chart>
</card>
</template>
<script>
import Vue from "vue";
import Chartkick from "vue-chartkick";
import Chart from "chart.js";
Vue.use(Chartkick.use(Chart));
export default {
props: ["card"],
data() {
return {
chart_data: {
"2017-05-13": 2,
"2017-05-14": 5
}
};
}
};
</script>
<style scoped>
.flex {
min-height: 950px;
}
</style>
The card is working and displaying on the dashboard. I simply placed span tags and output a name to confirm this as can be seen here:
I played with the CSS of the box to make sure the chart wasn't being hidden as can be seen from the changed shape.
I can't seem to get the chart to display and am unsure of what is being done wrong.

Your component is not rendered in the page, you should compile your assets and register them in the NovaServiceProvider
npm run dev
And in the boot function in your Laravel app
use Laravel\Nova\Events\ServingNova;
class NovaServiceProvider extends NovaApplicationServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$this->app->booted(function () {
$this->routes();
});
Nova::serving(function (ServingNova $event) {
Nova::script('{{ component }}', __DIR__.'/../dist/js/card.js');
});
}
From the Docs

Related

Laravel + SPA VueJs not giving error for unknown component

<template>
<div>
<test-component />
</div>
</template>
<script>
//import TestComponent from '../path-to-components/TestComponent';
export default {
name: 'SomeRandomComponent',
components: {
TestComponent,
}
}
</script>
Expected Behaviour:
The application should give some console error if there is a problem with the imports or anything else similar to this.
Current Behaviour:
The page get blank in the browser and there is no error in console even if the import statement is commented out.
Code for reference
app.js
import Vue from 'vue';
import router from '~/router';
import App from '~/components/App';
new Vue({
router,
...App
})
router.js
export default [
{ path: '/some-path', name: 'testing', component: import( `~/pages/path-to-component`).then(m => m.default || m) },
]
App.vue
<template>
<div id="app">
<loading ref="loading" />
<transition name="page" mode="out-in">
<component :is="layout" v-if="layout" />
</transition>
</div>
</template>
<script>
import Loading from './Loading'
// Load layout components dynamically.
const requireContext = require.context('~/layouts', false, /.*\.vue$/)
const layouts = requireContext.keys()
.map(file =>
[file.replace(/(^.\/)|(\.vue$)/g, ''), requireContext(file)]
)
.reduce((components, [name, component]) => {
components[name] = component.default || component
return components
}, {})
export default {
el: '#app',
components: {
Loading
},
data: () => ({
layout: null,
defaultLayout: 'default'
}),
metaInfo () {
const { appName } = window.config
return {
title: appName,
titleTemplate: `%s ยท ${appName}`
}
},
mounted () {
this.$loading = this.$refs.loading
},
methods: {
/**
* Set the application layout.
*
* #param {String} layout
*/
setLayout (layout) {
if (!layout || !layouts[layout]) {
layout = this.defaultLayout
}
this.layout = layouts[layout]
}
}
}
</script>
I am assuming that you are using Vue2 since Vue3 is in beta.
The first problem I see with your code, is that your <div id="app"> is inside a Vue component.
Declarative Rendering
What happening is that everything is compile, but you are trying to render Vue inside a component that does not exist.
Instead, create a div element inside the html or blade.php file that is loaded by the client. For my part, I use a blade layout like this:
//resources/views/layouts/app.blade.php
...
</head>
<body>
<div id="app" v-cloak> //This is plain loaded when client render views, then, when script will initiate, Vue will be able to access everything inside this.
<navbar v-bind:core="core"></navbar> //There is my navbar which is a Vue component.
<div class="boxed">
<div id="content-container">
#yield('content') //Blade component are injected there. since it's inside the <div id="app">, thoses component can include Vue directive/component.
</div>
...
Another thing that seems a problem is that you are initiating Vue inside a Vue component. Things are that Vue is a package and compiled into javascript in the end. But, to make all the magic happen, you need to have somwhere to initiate all this. In that case, your App.js file should look something like this:
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app',
});
This file is the one created by default by laravel for Vue template on fresh Laravel 8 install.
The difference between import and require is that import create a promise.
You don't want a promise there, because you want that file to be execute at the moment the client will begin to render your page.
Following thoses recommendation, I think you will be able to get your app working quickly and Vue will start logging error into your console.

Laravel + Bootstrap-Vue Table not accepting data

I'm currently playing with Laravel Spark and I'm slowly learning the Vue.js system.
I have a bunch of data I want to display in a table that is pulled from AWS DynamoDB. I am successfully parsing this data in sorts of ways and can display the data in a standard static Bootstrap table. I'm now trying to use the Vue.js version and I cannot for the life of me get this data to display at all. If I insert dummy data into the Vue Component, the dummy data shows so it must be the way I'm passing the data in.
My code as follows:
TableController.php
public function show()
{
$data = $this->fetchAWSData($condition); // This is my separate AWS method
return view('table')->with('items', $data);
}
table.blade.php
#extends('spark::layouts.app')
#section('content')
<home :user="user" inline-template>
<div class="container-fluid" style="text-align: left">
<h1>Data</h1>
<MyTable items={{ $items }}></MyTable>
</div>
</home>
#endsection
MyTable.vue
<template>
<b-table striped hover :items=items></b-table>
</template>
<script>
export default {
data() {
return {
items: this.items
}
}
}
</script>
What am I doing wrong here? I've tried formatting my data all sorts of ways; JSON, manually, Arrays... nothing works. So it must be the way I'm passing it in.
Any insight would be AMAZING :)
You have to use props to be able to pass attributes to Vue's components.
MyTable.vue
...
<script>
export default {
props: ['items'],
}
</script>
Then you can pass data to component:
<MyTable :items="{{ $items }}">

react not receiving prop from html

I have a react component in a file named ts.js:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
export default class Ts extends React.Component {
constructor(props) {
super(props);
var expected = {
lowercase:'Onlylowercase',
snakeCase:'justSnakeCase',
ProperCase: 'AndProperCase'
};
console.log("expected:",expected);
console.log("props:",props);
console.log("this.props",this.props);
console.log("props.lowercase",props.lowercase);
this.state={'lowercase':this.props.lowercase};
};
render() {
return NULL;
}
}
if (document.getElementById('ts')) {
ReactDOM.render(<Ts />, document.getElementById('ts'));
}
I also have a html page from where this is called:
<html>
<head>
<title>My TS</title>
</head>
<body>
<Ts lowercase="onlylowercase" id="ts" snakeCase="justSnakeCase" ProperCase="AndProperCase">
</Ts>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
My issue is I can't get the values lowercase="onlylowercase" id="ts" snakeCase="justSnakeCase" ProperCase="AndProperCase" recognised as props in the constructor. I need to pass in some stuff from the html to populate the initial state of the component.
When I open the HTML with Chrome console open I get:
expected: {lowercase: "Onlylowercase", snakeCase: "justSnakeCase", ProperCase: "AndProperCase"}
props: {}
__proto__: Object
or it is this.props?: {}
__proto__: Object
props.lowercase undefined
this.props.lowercase undefined
undefined
undefined
I am expecting props to be a javascript object with properties of lowercase, snakeCase and ProperCase, like the var expected.
I don't think I need to use componentWillReceiveProps - as I am trying to follow the pattern describe in the documentation here:
https://reactjs.org/docs/react-component.html#constructor
and pass in props as html attributes as described here:
https://reactjs.org/docs/components-and-props.html
I have excluded from this post the detail of the node modules and javascript includes - as the Ts component's constructor is being called which demonstrates the Ts class is "there" and my npm config is OK - it is including react and other required modules. The {{ asset() }} function is a Laravel function. The html is part of a blade template in a Laravel app.
Can anyone see what I am doing wrongly?
Your syntax is wrong. React doesn't creat a new html tag like "". You only can use tag in react component. So the right syntax is in html replace
<Ts lowercase="onlylowercase" id="ts" snakeCase="justSnakeCase" ProperCase="AndProperCase">
</Ts>
To <div id="ts"></div>
and go add to before
<script>
var lowercase="whatever";
var snakeCase="snakeCase";
...
</script>
And change to
if (document.getElementById('ts')) {
ReactDOM.render(<Ts lowercase={lowercase} snakeCase={snakeCase} />, document.getElementById('ts'));
}
ReactDOM will find a dom with id is "ts" and replace it by your ts component.

Where does `billlable` come from in Laravel Spark's `update-payment-method-stripe` Component?

If Laravel Spark, there's a vue component with the following inline template
<spark-update-payment-method-stripe :user="user" :team="team" :billable-type="billableType" inline-template>
/* ... */
<div class="pull-right">
<span v-if="billable.card_last_four">
<i :class="['fa', 'fa-btn', cardIcon]"></i>
************#{{ billable.card_last_four }}
</span>
</div>
/* ... */
</spark-update-payment-method-stripe>
This template include the variable billable.card_last_four.
If I track down the definition file for the component, I see this
#File: resources/assets/js/spark-components/settings/payment-method/update-payment-method-stripe.js
var base = require('settings/payment-method/update-payment-method-stripe');
Vue.component('spark-update-payment-method-stripe', {
mixins: [base]
});
and if I track down the base component, I see a vue component defined
#File: spark/resources/assets/js/settings/payment-method/update-payment-method-stripe.js
module.exports = {
props: ['user', 'team', 'billableType'],
/* ... */
However, none of these components seem to define billable anywhere. I see a lot of references to this.billable.
#File: spark/resources/assets/js/settings/payment-method/update-payment-method-stripe.js
/* ... */
this.form.address = this.billable.billing_address;
this.form.address_line_2 = this.billable.billing_address_line_2;
this.form.city = this.billable.billing_city;
this.form.state = this.billable.billing_state;
this.form.zip = this.billable.billing_zip;
this.form.country = this.billable.billing_country || 'US';
/* ... */
placeholder() {
if (this.billable.card_last_four) {
return `************${this.billable.card_last_four}`;
}
return '';
}
/* ... */
Where does this billable property come from? I assume Vue's doing some form of meta-programming and/or magic to populate this, but I'm not familiar enough with Vue to know what's going on.
Got the answer I was looking for with help from Bert Evans and thanksd above, as well as the Chrome VueJS debugger
The billable property was, indeed, a computed property. However, it wasn't computed locally in the update-payment-method-stripe.js definition file. Instead, Spark has a vue-bootstrap.js which contains the following
Vue.mixin(require('./mixin'));
It turns out VueJS has a global mixin feature which (appears to?) add a method to every component in the system. The mixin module looks like this
#File: spark/resources/assets/js/mixin.js
module.exports = {
computed: {
/**
* Get the billable entity.
*/
billable() {
/* ... */
},
/* ... */
}
};
Which means every component in spark will have this computer billable property.

use parse react query results as an html tag attribute

This is my first time asking a question so I am a true SO newbie. I am currently working on a mobile app and I am using Parse React and Ratchet to build it. I have read the React documentations on FB github and apparently do not understand all enough to solve some problems. One of my problems is using the results of a Parse Query in the observe function of the declared ParseComponent as a value of a rendered react component, which in turn attempts to render the passed value as HTML. Below is the parent object:
export default class CategoryPage extends ParseComponent
{
observe(props,state){
return{
category: new Parse.Query('BusinessCategory').equalTo("objectId", this.props.categoryId)
};
}
render() {
return (
<div>
<Header text={this.data.category.objectId} back="true"/>
<div className="content">
<BusinessList categoryId={this.data.category.objectId}/>
</div>
<NavBar />
</div>
);
}
};
Notice I am passing the objectId of the category found in the Query as a text attribute of the Header React component. I am expecting Header as a child to use the passed property as follows:
var Header = React.createClass({
render: function () {
return(
<header className="bar bar-nav">
<h1 className="title">{this.props.text}</h1>
</header>
);
}
});
However the h1 is not rendering anything! I am thinking that this.data.category.objectId is a string and therefore should be rendered in the h1 tag as a string.
I do appreciate your answers very much.

Resources