Blank Data by Fetching data from DB using Laravel 9 and Vue.js 3 and Axios - vue.js

Hello i using Laravel 9 and Vue.js 3, with Axio and i am trying to fecht some data from my data base, to appear inside a select list options, however i am not getting anything (neither any error, just blank data...)
I created my model Produto
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Produto extends Model
{
use HasFactory;
protected $table = "produto";
protected $guarded = [];
}
created the correct migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('produto', function (Blueprint $table) {
$table->id();
$table->string("nome");
$table->double("preco");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('produto');
}
};
Created my controller ProdutoController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Produto;
class ProdutoController extends Controller
{
/**
*Retorna os dados dos Produtos
*
* #return void
*/
public function getProdutos()
{
$data = Produto::get();
return response()->json($data);
}
}
Defined my route
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProdutoController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('get_produtos', [ProdutoController::class, 'getProdutos']);
//Route::post('produtos', [ProdutoController::class, 'setProdutos']);
For testing i tried localhost:8000/get_produtos and it appeared my data as expected, so i think this part is correct
[{"id":1,"nome":"Telemovel","preco":124.55,"created_at":null,"updated_at":null},{"id":2,"nome":"Tablet","preco":600.99,"created_at":null,"updated_at":null},{"id":3,"nome":"Portatil","preco":501,"created_at":null,"updated_at":null},{"id":4,"nome":"Caneta","preco":2.55,"created_at":null,"updated_at":null}]
In my template i used this Select
<div :id="selectProdutoID" class="row">
<div :id="optionId" class="col-sm-6" >
<select :id="selectId" class=' form-select form-control-md' v-model='prod' #change="onchange($event)">
<option v-for='data in produto' :value='data.id'>{{ data.nome }} </option>
</select>
</div>
And finally here is my script
<script>
export default{
name:"app",
components: {
},
data() {
return{
blankID:"blank",
tituloID:"titulo",
ClienteID:"nomeCliente",
selectId:"selectID",
dropID:"drop",
adicionarID:"adicionarId",
selectProdutoID:"selectProduto",
optionId:"optionId",
qtdID:"qtdId",
boxId:"boxId",
produto: [],
onchange(e){
console.log(e.target.value);
}
}
},
methods:{
getProdutos: function(){
axios.get('get_produtos')
.then(function (response) {
this.produtos = response.data;
}.bind(this));
}
},
created: function(){
this.getProdutos()
}
}
</script>
It doesn't even get me an error, just a select with empty content , and i tried to check other solutions i found here, but nothing worked for now. I believe the error is happening somewhere in the the template/script part, but i´ve been trying everything i found and still with no luck
Thank you in advance
EDIT:
Found out this tutorial https://www.tutsmake.com/laravel-9-vue-js-axios-get-request-tutorial/
and then changed my script methods to
methods: {
getProdutos(){
axios.get('/get_produtos')
.then((response)=>{
this.produtos = response.data.produtos
})
}
},
created() {
this.getProdutos()
}
However data continues to not appear on my select

Found a solution to my problem. For some reason if i use «this» directly Axios doesn't work, so i had to create a variable, and it worked
methods: {
getProdutos(){
var vm = this
axios.get('/get_produtos')
.then((response)=>{
vm.produtos = response.data
})
}
},
created() {
this.getProdutos()
}

Related

Handle paste event in vue2-editor

I'm using this text editor https://github.com/davidroyer/vue2-editor that is based on Quilljs
I want to handle the paste event so it pastes only the plain text without any format but seems in the documentation that paste is not a supported event by default.
Is there any way to add the paste event?
I've already tried using v-on:paste in the Editor and adding the Quill custom module Clipboard but haven't had any success.
As I didn't find a way of doing it with the library I did it with the DOM
onPaste() {
const x = document.getElementById("removePasteFormat");
console.log(x);
x.addEventListener("paste", (e) => {
e.stopPropagation();
e.preventDefault();
let text = e.clipboardData.getData("text/plain");
// access the clipboard using the api
if (document.queryCommandSupported("insertText")) {
document.execCommand("insertText", false, text);
} else {
document.execCommand("paste", false, text);
}
});
},
Added the id to the div containing the text editors like this:
<div id="removePasteFormat"> *<<Here goes the text editor component>>* </div>
And register the method on mounted()
mounted() {
this.onPaste();
},
I think it would be good to make a plugin.
I made it simple.
src/utils/vue2Plugin/clipboard.ts
import Delta from 'quill/node_modules/quill-delta';
import Clipboard from 'quill/modules/clipboard';
import { Quill } from 'vue2-editor';
export class CustomClipboardPlugin extends Clipboard {
public quill!: Quill;
public options: any = {};
constructor(quill: Quill) {
super(quill, {
matchers: [],
});
this.quill = quill;
this.quill.root.addEventListener('paste', this.onPaste.bind(this), true);
}
onPaste(event: ClipboardEvent) {
event.preventDefault();
event.stopPropagation();
const range = this.quill.getSelection(true);
if (range === null) return;
let _textHtml;
if (event.clipboardData?.getData('text/html')) {
_textHtml = event.clipboardData?.getData('text/html');
} else if (event.clipboardData?.getData('text/plain')) {
_textHtml = `<p>${event.clipboardData?.getData('text/plain')}</p>`;
}
if (_textHtml) {
const pastedDelta = this.quill.clipboard.convert(_textHtml);
const delta = new Delta()
.retain(range.index)
.delete(range.length)
.concat(pastedDelta);
this.quill.updateContents(delta, Quill.sources.USER);
this.quill.setSelection(delta.length() - range.length, 0, Quill.sources.SILENT);
}
}
}
vue file
<template>
...
<VueEditor
...
:custom-modules="customModulesForEditor"
...
/>
...
</template>
// script
import CustomClipboardPlugin fro 'src/utils/vue2Plugin/clipboard.ts';
...
data() {
return {
customModulesForEditor: [{ alias: 'clipboard', module: CustomClipboardPlugin }],
};
},
...
I was wondering the same and came up with the following solution.
1 - Use the :editorOptions option referenced here
<template>
VueEditor(:editorOptions="editorSettings")
</template>
2 - Fill with the module.clipboard module with the option described here
3 - You can then handle the paste with your personal function (applied after quill's matcher). I've written mine following this answer on github
<script>
data() {
return {
editorSettings: {
modules: {
clipboard: {
matchers: [[Node.ELEMENT_NODE, this.customQuillClipboardMatcher]]
}
}
}
}
},
methods: {
customQuillClipboardMatcher(node, delta) {
delta.ops = delta.ops.map((op) => {
return {
insert: op.insert
}
})
return delta
},
}
</script>

Shopware 6 | Custom field of null

I try to create a custom field when I activate my plugin.
This custom field I also find in my database but when I try to load it in my vue component the field is null. I build it like the example from shopware. I do the same as in the GitHub example, but it does not work.
PluginName.php
...
public function activate(ActivateContext $activateContext): void
{
try {
/** #var EntityRepository $repo */
$repo = $this->container->get('custom_field.repository');
// Check if custom fields already exist
$result = $repo->searchIds((new Criteria())->addFilter(new EqualsAnyFilter('name', [
self::PRODUCT_CUSTOMIZABLE,
])), $activateContext->getContext());
if ($result->getTotal() > 0) {
return;
}
/* #var EntityRepository */
$repo->create([
[
'name' => self::PRODUCT_CUSTOMIZABLE,
'type' => CustomFieldTypes::BOOL,
]
], Context::createDefaultContext());
} catch (Exception $e) {
dd($e);
}
}
My Vue component.
import template from './personal-product-canvas.html.twig';
const { mapState, mapGetters } = Shopware.Component.getComponentHelper();
Shopware.Component.register('personal-product-canvas', {
template,
data() {
return {
setPosKey: 0
};
},
computed: {
...mapState('swProductDetail', [
'product'
]),
...mapGetters('swProductDetail', [
'isLoading'
]),
isCustomizable: {
get() {
return (this.product.customFields || {}).personal_product_customizable || false;
},
set(value) {
this.$set(this.product.customFields, 'personal_product_customizable', value);
if (value) this.initializeCanvas();
}
},
},
});
I had the same problem until I noticed that I had edited the custom fields in the "German" language, but the shop was set to English.
Filling out the additional fields for the English language helped me.
Maybe it will help you too.

Laravel /broadcasting/auth Always forbidden with 403 Error

I tried many solutions but no one works for me
I've installed Laravel echo and pusher js and Pusher/Pusher
#bootstrap.js
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true,
});
#.env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=my_id
PUSHER_APP_KEY=my_key
PUSHER_APP_SECRET=my_secret
PUSHER_APP_CLUSTER=eu
my event file NewMessage
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('messages.'. $this->message->to);
}
public function broadcastWith()
{
return ["message" => $this->message];
}
}
channel.php
Broadcast::channel('messages.{id}', function ($user, $id) {
return $user->id === (int) $id;
});
Vue App JS code
mounted(){
Echo.private(`messages${this.user.id}`)
.listen('NewMessage', (e) => {
this.handleIncoming(e.message)
});
},
methods:{
saveNewMessage(msg){
this.messages.push(msg);
},
handleIncoming(message){
if(this.selectedContact && message.from == this.selectedContact.id ){
this.saveNewMessage(message);
return;
}
alert(message.text);
}
}
Api.php
Route::post('/conversation/send', 'Api\ContactController#sendNewMessage');
Contact Controller
public function sendNewMessage(Request $request)
{
$message = Message::create([
'from' => $request->sender_id,
'to' => $request->receiver_id,
'text' => $request->text
]);
broadcast(new NewMessage($message));
return response()->json($message);
}
I also read the official documentation everything is going good but I didn't figure out why, it's a throwing error. Have any idea?
I figure out why it is every time shows auth forbidden or doesn't display auth
Solution:
you need to double-check your PUSHER_APP_KEY because if it is not set correctly, it will through error because our stream not connected with pusher
PUSHER_APP_KEY="PUT KEY HERE"
If you are very sure that your app key is correct then go to the Network tab and click on your pusher app key which like e70ewesdsdssew0
If it is displaying the result like this
{"event":"pusher:connection_established","data":"{\"socket_id\":\"131139.31305364\",\"activity_timeout\":120}"}
your API key is good
if it not correct it will display an error like this
{"event":"pusher:error","data":{"code":4001,"message":"App key 3fdsfdfsdfsd not in this cluster. Did you forget to specify the cluster?"}}
Also, don't forget to put the cluster key
PUSHER_APP_CLUSTER=eu

Mat-select is not showing the options: Angular 10

I wonder what is wrong with my use of mat-select. Because it is not showing the list of options:
<form>
<mat-form-field appearance="standard">
<mat-label>New Error Type</mat-label>
<mat-select [(ngModel)]="selectedNewErrorCode" name="faultType">
<mat-option *ngFor="let faultType of faultTypes" [value]="faultType.code">
{{faultType.label}}
</mat-option>
</mat-select>
</mat-form-field>
<p>Selected error: {{selectedNewErrorCode}}</p>
</form>
The component which is displayed in a modal is the following.
/** Imports animations */
import {slideInAnimation} from '../../animations';
/** Imports models */
import {StackTraceView} from '../../objects/stack-trace-view.model';
import {FaultType} from '../../objects/fault-type.model';
#Component({
selector: 'app-consult-details',
templateUrl: './consult-details.component.html',
styleUrls: ['./consult-details.component.sass'],
animations: [slideInAnimation]
})
export class ConsultDetailsComponent implements OnInit {
constructor() {
}
public flux: StackTraceView;
public modifState = false;
/** Used in resetting the form */
originalFlux: string;
faultTypes: FaultType[];
/** determines if the original error flux should be visible or not */
public originalErrorVisible = false;
/** Sets the new fault type for reanalysing the stack trace */
selectedNewErrorCode: string;
ngOnInit(): void {
}
modifyFlux() {
this.modifState = !this.modifState;
}
sendFlux() {
console.log(`The flux changed to ${this.flux.originalFlux}`);
}
/** Reste the form to its original state */
resetForm() {
document.getElementById('toBeReset').innerHTML = this.originalFlux;
this.flux.originalFlux = this.originalFlux;
this.modifState = false;
}
/** Sets the visibility of the original error flux to flse if it is true and vice versa */
isOriginalErrorVisible() {
this.originalErrorVisible = !this.originalErrorVisible;
}
}
The entire component is displayed in a modal. The variable faultTypes is fed in when the modal is called in the parent component. The corresponding code in the parent component is the following:
const detailsContent = this.specificReportList.filter(
entry => entry.messageId === originalMessageId
)[0];
const modalRef = this.modalService.open(ConsultDetailsComponent, {
size: 'xl',
ariaDescribedBy: 'Details'
});
/** The input sata for the pop-up component */
modalRef.componentInstance.flux = detailsContent;
modalRef.componentInstance.originalFlux = detailsContent.originalFlux;
modalRef.componentInstance.faultTypes = this.faultTypeList;
modalRef.result.then((result) => {
this.closeResult = `Close with ${result}`;
}, (reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}```
As a final comment the variable faulttypes is well fed in via the
parent component and when I use nromal select and option I do not have
any problem; The code works very well, the only problem is when I use
mat-select which is important for me beacuse It gives a unifrom look
and feel to my application.

Technique for jquery change events and aurelia

I need to find a reliable solution to making the two frameworks play nicely.
Using materialize-css, their select element uses jquery to apply the value change. However that then does not trigger aurelia in seeing the change. Using the technique of...
$("select")
.change((eventObject: JQueryEventObject) => {
fireEvent(eventObject.target, "change");
});
I can fire an event aurelia sees, however, aurelia then cause the event to be triggered again while it's updating it's bindings and I end up in an infinite loop.... Stack Overflow :D
Whats the most reliable way of getting the two to play together in this respect?
I have worked with materialize-css + aurelia for a while and I can confirm that the select element from materialize is quite problematic.
I just wanted to share one of my solutions here in case anyone wants some additional examples. Ashley's is probably cleaner in this case. Mine uses a bindable for the options instead of a slot.
Other than that the basic idea is the same (using a guard variable and a micro task).
One lesson I learned in dealing with 3rd party plugins and two-way data binding is that it helps to make a more clear, distinct separation between handling changes that originate from the binding target (the select element on the DOM) and changes that originate from the binding source (e.g. the ViewModel of the page containing the element).
I tend to use change handlers with names like onValueChangedByBindingSource and onValueChangedByBindingTarget to deal with the different ways of syncing the ViewModel with the DOM in a way that results in less confusing code.
Example: https://gist.run?id=6ee17e333cd89dc17ac62355a4b31ea9
src/material-select.html
<template>
<div class="input-field">
<select value.two-way="value" id="material-select">
<option repeat.for="option of options" model.bind="option">
${option.displayName}
</option>
</select>
</div>
</template>
src/material-select.ts
import {
customElement,
bindable,
bindingMode,
TaskQueue,
Disposable,
BindingEngine,
inject,
DOM
} from "aurelia-framework";
#customElement("material-select")
#inject(DOM.Element, TaskQueue, BindingEngine)
export class MaterialSelect {
public element: HTMLElement;
public selectElement: HTMLSelectElement;
#bindable({ defaultBindingMode: bindingMode.twoWay })
public value: { name: string, value: number };
#bindable({ defaultBindingMode: bindingMode.oneWay })
public options: { displayName: string }[];
constructor(
element: Element,
private tq: TaskQueue,
private bindingEngine: BindingEngine
) {
this.element = element;
}
private subscription: Disposable;
public isAttached: boolean = false;
public attached(): void {
this.selectElement = <HTMLSelectElement>this.element.querySelector("select");
this.isAttached = true;
$(this.selectElement).material_select();
$(this.selectElement).on("change", this.handleChangeFromNativeSelect);
this.subscription = this.bindingEngine.collectionObserver(this.options).subscribe(() => {
$(this.selectElement).material_select();
});
}
public detached(): void {
this.isAttached = false;
$(this.selectElement).off("change", this.handleChangeFromNativeSelect);
$(this.selectElement).material_select("destroy");
this.subscription.dispose();
}
private valueChanged(newValue, oldValue): void {
this.tq.queueMicroTask(() => {
this.handleChangeFromViewModel(newValue);
});
}
private _suspendUpdate = false;
private handleChangeFromNativeSelect = () => {
if (!this._suspendUpdate) {
this._suspendUpdate = true;
let event = new CustomEvent("change", {
bubbles: true
});
this.selectElement.dispatchEvent(event)
this._suspendUpdate = false;
}
}
private handleChangeFromViewModel = (newValue) => {
if (!this._suspendUpdate) {
$(this.selectElement).material_select();
}
}
}
EDIT
How about a custom attribute?
Gist: https://gist.run?id=b895966489502cc4927570c0beed3123
src/app.html
<template>
<div class="container">
<div class="row"></div>
<div class="row">
<div class="col s12">
<div class="input-element" style="position: relative;">
<select md-select value.two-way="currentOption">
<option repeat.for="option of options" model.bind="option">${option.displayName}</option>
</select>
<label>Selected: ${currentOption.displayName}</label>
</div>
</div>
</div>
</div>
</template>
src/app.ts
export class App {
public value: string;
public options: {displayName: string}[];
constructor() {
this.options = new Array<any>();
this.options.push({ displayName: "Option 1" });
this.options.push({ displayName: "Option 2" });
this.options.push({ displayName: "Option 3" });
this.options.push({ displayName: "Option 4" });
}
public attached(): void {
this.value = this.options[1];
}
}
src/md-select.ts
import {
customAttribute,
bindable,
bindingMode,
TaskQueue,
Disposable,
BindingEngine,
DOM,
inject
} from "aurelia-framework";
#inject(DOM.Element, TaskQueue, BindingEngine)
#customAttribute("md-select")
export class MdSelect {
public selectElement: HTMLSelectElement;
#bindable({ defaultBindingMode: bindingMode.twoWay })
public value;
constructor(element: Element, private tq: TaskQueue) {
this.selectElement = element;
}
public attached(): void {
$(this.selectElement).material_select();
$(this.selectElement).on("change", this.handleChangeFromNativeSelect);
}
public detached(): void {
$(this.selectElement).off("change", this.handleChangeFromNativeSelect);
$(this.selectElement).material_select("destroy");
}
private valueChanged(newValue, oldValue): void {
this.tq.queueMicroTask(() => {
this.handleChangeFromViewModel(newValue);
});
}
private _suspendUpdate = false;
private handleChangeFromNativeSelect = () => {
if (!this._suspendUpdate) {
this._suspendUpdate = true;
const event = new CustomEvent("change", { bubbles: true });
this.selectElement.dispatchEvent(event)
this.tq.queueMicroTask(() => this._suspendUpdate = false);
}
}
private handleChangeFromViewModel = (newValue) => {
if (!this._suspendUpdate) {
$(this.selectElement).material_select();
}
}
}
Ok, I spent entirely too long getting this one answered the way I wanted, but more on that later. The actual answer to stop the infinite loop is fairly simple, so let's look at it first. You need to have a guard property, and you'll need to use Aurelia's TaskQueue to help unset the guard property.
Your code will look a little something like this:
$(this.selectElement).change(evt => {
if(!this.guard) {
this.guard = true;
const changeEvent = new Event('change');
this.selectElement.dispatchEvent(changeEvent);
this.taskQueue.queueMicroTask(() => this.guard = false);
}
});
Notice that I'm using queueing up a microtask to unset the guard. This makes sure that everything will work the way you want.
Now that we've got that out of the way, let's look at a gist I created here. In this gist I created a custom element to wrap the Materialize select functionality. While creating this, I learned that select elements and content projection via slot elements don't go together. So you'll see in the code that I have to do some coding gymnastics to move the option elements over from a dummy div element into the select element. I'm going to file an issue so we can look in to this and see if this is a bug in the framework or simply a limitation of the browser.
Normally, I would highly recommend creating a custom element to wrap this functionality. Given the code I had to write to shuffle nodes around, I can't say that I highly recommend creating a custom element. I just really recommend it in this case.
But anyways, there you go!