I'm using Quasar to create a tree:
<q-tree v-if="tree"
:nodes="tree"
node-key="label"
default-expand-all
/>
If I manually enter the node data and use the handler node property to apply a click function to my nodes, it works great:
data () {
return {
tree: [ { id: 7, label: 'Master Stateroom', icon: 'crop_3_2', children: [ { id: 4, label: 'Center Bilge Compartment', icon: 'crop_3_2', handler: (node) => this.goCompartment(node) } ], handler: (node) => this.goRoom(node) } ]
}
},
and my basic, testing methods:
methods: {
goRoom (room) {
alert(room.id)
},
goCompartment (compartment) {
alert(compartment.label)
}
}
All is good, however, I want to load in my nodes from a database and I'm having trouble getting the handler function to work - it's just a string.
An excerpt from my API:
return [ 'id' => $this->id, 'label' => $this->name, 'icon' => 'crop_3_2', 'children' => $children, 'handler' => '(node) => this.goRoom(node)' ];
I know I don't want just a string there, it needs to be evaluated as a function. If I review the data in Vue Devtools, I see the handler passed from my API is just a string and the hardcoded, local version, shows up as a function.
Anyone have any tips for passing that correctly from the API to the vue component?
Related
I have a nuxt frontend using the vue-filepond adapter, users have the option to upload images with there post. This is then send to a laravel API that will handle the request.
<client-only>
<file-pond
name="image"
ref="pond"
class="filepond"
:allow-multiple="false"
accepted-file-types="image/jpeg, image/png"
server="http://127.0.0.1:8000/api/posts"
allowRevert="false"
:files="form.image"
/>
</client-only>
using mostly default filepond options,
data() {
return {
errors: [],
form: {
title: '',
content: '',
image: [],
}
}
},
Data is uploaded to the api like so
methods: {
createPost() {
this.$axios.$post('http://127.0.0.1:8000/api/posts', this.form)
this.$toast.show({
type: 'success',
title: 'Success',
message: 'Your post has been created'
})
}
}
Now since filePond is async the file is uploaded earlier then my form when I post it.
so in the laravel part
public function store(Request $request): void
{
if ($request->hasFile('image')) {
$path = Storage::putFile('avatars', $request->file('image'));
}
$request->validate([
'title' => 'required|string|max:24',
'content' => 'required|string|max:254',
'image' => 'nullable|image'
]);
Post::create([
'title' => $request->get('title'),
'slug' => Str::slug($request->get('title'), '-'),
'content' => $request->get('content'),
'image' => $path ?? null
]);
}
The image would be stored, but if I click submit on my form to upload a title and some content the ìmage part in the Post::create method is always NULL.
How can I make it so that filePond is not uploaded async anymore? so that when I hit submit on my form the title , content and image are all uploaded equally
Figured it out thanks to kissu and reading through filePond's docs.
const file = this.$refs.pond.getFiles()[0].file
const data = new FormData()
data.append('title', this.form.title)
data.append('content', this.form.content)
data.append('image', file)
this.$axios.$post('http://127.0.0.1:8000/api/posts', data)
and in your backend (laravel in my case)
if ($request->hasFile('image') && $request->file('image')->isValid()) {
$post->addMediaFromRequest('image')->toMediaCollection('image');
}
I am using the laravel-charts package in Laravel 7. I added the datalabels plugin for chartjs into the Chart object like this:
$this->options = [
'responsive' => true,
'maintainAspectRatio' => false,
'legend' => [ 'display' => false ],
'plugins' => [
'datalabels' => [
'color' => 'white',
'weight' => 'bold',
'font' => ['size' => 14],
'formatter' => ''
]
]
In another version when I was using vue.js and vue-chartjs, I was able to format the lable using this:
plugins: {
datalabels: {
formatter: function(value, context) {
return '$' + Number(value).toLocaleString();
},
}
}
As you can see, the javascript is passed as a PHP array. I cannot figure out how to pass that formatter to my laravel-charts version.
Any help is greatly appreciated.
Laravel Charts plugins option has to be a string that's representing a plain Javascript object. I couldn't find any actual documentation, but you can read a related issue here "How to use ChartsJs plugin Datalabels js?".
You'll have to pass it like this:
$chart = new ChartTest;
$chart->labels(['One Thousand', 'Two Thousand', 'Three Thousand', 'Four Thousand']);
$chart->dataset('My dataset', 'bar', [1000, 2000, 3000, 4000]);
$chart->options([
// The whole plugins element is a string representing a JS object with plugins options
'plugins' => "{
datalabels: {
color: 'red',
font: {
size: 14,
weight: 'bold'
},
formatter: (value) => `\\$\${value}`
}
}"
]);
return view('chart', ['chart' => $chart]);
Will apply chartjs-plugin-datalabels options:
PS: The weight property has to be inside the font object like in my example.
Is there any possibility to invalidate or delete PageCache for a particular action.
Consider this:
class SiteController extends Controller
{
public function behaviors()
{
return [
'pageCache' => [
'class' => PageCache::className(),
'duration' => Yii::$app->params['cacheTime'], // seconds
'variations' => [
Yii::$app->language,
Yii::$app->request->get('id'),
],
],
];
}
public function actionIndex( $id )
{
// action code
}
}
And now I want to remove/invalidate cache for
action en/site/index?id=1
Currently I am thinking to write some code in a console app but do not know how to achieve this.
EDIT1: I try to rebuild-invalidate cache manually for a specific action. The code can't relay on 'dependency' because it is almost impossible to implement for that action.
EDIT2: The task is to rebuild cache only for the specific action (page) leave other cache intact.
You can use TagDependency for more granular invalidation:
public function behaviors()
{
return [
'pageCache' => [
'class' => PageCache::className(),
'duration' => Yii::$app->params['cacheTime'], // seconds
'variations' => [
Yii::$app->language,
Yii::$app->request->get('id'),
],
'dependency' => new \yii\caching\TagDependency([
'tags' => [
Yii::$app->requestedRoute,
Yii::$app->request->get('id'),
],
]),
],
];
}
To invalidate cache:
TagDependency::invalidate(Yii::$app->cache, [
'site/index', // route of action
123, // ID of page
]);
If someone else needs ...
Yii2 does not provide a native function to invalidate the cache of a specific page, however there is the delete function of the cache component. It would however be necessary to know the generated key for the requested page but the function that generates this key is protected (calculateCacheKey ()). In this way, the best way would be to create your own class extending \yii\filters\PageCache.
'pageCache' => function () {
return new class extends \yii\filters\PageCache{
public function init(){
parent::init();
$this->except = ['index'];
$this->duration = Yii::$app->params['cacheTime'], // seconds;
$this->variations = [
Yii::$app->language,
Yii::$app->request->get('id'),
];
if(Yii::$app->request->get('IC') == 1)
Yii::$app->cache->delete($this->calculateCacheKey());
}
public function beforeCacheResponse(){
return Yii::$app->request->get('IC') != 1;
}
};
},
In the provided code, for simplicity, I am using an anonymous class (PHP 7).
Instead you can create your class as you wish and inform its path as the 'class' parameter, as seen in the configuration displayed in the question.
Note that I am using a simple logic to invalidate the cache, checking if there is a GET parameter IC == 1, you can use whatever logic you want.
If after invalidating the cache you do not want a new cache to be created, simply return false in beforeCacheResponse, it is from \yii\filters\PageCache.
You can invalidate the cache by using dependencies
'pageCache' => [
...
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
http://www.yiiframework.com/doc-2.0/yii-filters-pagecache.html#$dependency-detail
If I understand correctly you are trying to disable caching only for a specific action and according to the DOCS you can use the following options to explicitly identify which action IDs to apply the cache filter OR which action IDs it should not.
$except array List of action IDs that this filter should not apply to. yii\base\ActionFilter
$only array List of action IDs that this filter should apply to.
The following should work for you
return [
'pageCache' => [
'class' => PageCache::className(),
'except'=>['index']
'duration' => Yii::$app->params['cacheTime'], // seconds
'variations' => [
Yii::$app->language,
Yii::$app->request->get('id'),
],
],
];
I'm building my first API and I have this nightmare scenario where I see myself defining the same request data in multiples places. How are people maintaining their key/value payloads?
Here's my VueJS component on the client side:
<script>
export default {
data() {
return {
name: '',
description: '',
selectedHeader: '',
}
},
computed: {
businessUrl() {
return this.name.replace(/[^A-Z0-9]+/ig, '') + '.test.com';
},
},
methods: {
preview() {
let data = {
'name': this.businessUrl,
'description' : this.description,
'selectedHeader': this.selectedHeader
};
axios.post('/builder/preview', data)
...
</script>
Server-side:
public function preview()
{
$validatedData = request()->validate([
'name' => 'required',
'description' => 'string',
'selectedHeader' => 'required',
]);
$business = new Business;
$business->name = request('name');
$business->description = request('description');
$business->header = request('selectedHeader');
return view('business', compact('business'));
}
If I want to change the 'name' field that is posted on my route I have to do it in up to 5 places if I include references in my HTML. Any patterns that people have developed to avoid this duplication?
i want to post ajax request using vue-resource this.$http.post request. it worked perfectly fine if i passed all validation rules but i want to get some validations if it fails. so far i keep getting 500 error if i don't fill out some input fields. it's hard for me to debug the error because it didn't appeared on the network tab.
here's what i've done so far
//my modal component
<script>
export default {
props: ['show'],
data() {
return {
input: {
id: '',
name: '',
address: '',
email: ''
},
errorInputs: {}
}
},
methods: {
createStudent() {
this.$http.post('/students', this.$data.input)
.then((response) => {
alert('added new row!)
}, (response) => {
console.log(response.data);
});
}
}
}
</script>
// my controller
public function store(Request $request) {
$validator = $this->validate($request,[
'id' => 'required',
'name' => 'required|unique:students',
'email' => 'required|unique:students|email',
'address' => 'required',
]);
if($validator->passes()){
Student::create($request->all());
return response()->json([], 201);
}
$errors = json_decode($validator->errors());
return response()->json([
'success' => false,
'message' => $errors
],422);
}
any helps and references would be appreciated. i am using laravel 5.3 and vue js 2
$this->validate() returns 422 error response alongside your validation errors, so you should get those errors in then() second callback (like you do now). Your vue component body should be like this:
{
data() {
// ...
},
createStudent() {
this.$http
.post('/students', this.input)
.then(this.handleSuccess, this.handleError)
},
handleSuccess(res) {
alert('student created')
},
handleError(res) {
if (res.status === 422) {
this.errorInputs = res.body
} else {
alert('Unkown error!')
}
}
}
Remember to add v-model="input.fieldName" properties to your inputs.
Remember to include your session token along with your post, unless of course you are disabling csrf tokens for that route.
Since Laravel 5.1 you can disable this in your verifytoken middleware
<?php namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as ...
class VerifyCsrfToken extends ... {
protected $except = [
'payment/*',
];
}