Before, I managed to insert an image file inside a file directory using FormData. But now, the FormData, which I am trying to use now for updating a wrong image, is returning an empty data even though I am passing the correct parameters/payload, which is the file that is an object. I tried using FormData.set for updating, and even experimenting on the forEach a bit, but none of them worked for me. In Quasar (which is like Bootstrap for Javascript), we get the rows for each data so we can update a row of data. Should I get the row for the image before the FormData finally gets a response?
Frontend
<template>
<div>
<q-table
:filter="filter"
title="Test Section"
:data="dtdata"
:columns="columns"
row-key="TestId"
>
<q-tr slot="body" slot-scope="props" :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
{{
col.value
}}
</q-td>
<q-td class="q-gutter-md">
<q-btn label="Edit" color="primary" #click.native="gatherData(props.row)" />
<q-btn label="Delete" color="red" #click.native="activateDel(props.row)" />
<q-btn label="Change Picture" color="green" #click.native="changeThisPic(props.row)" />
</q-td>
</q-tr>
</q-table>
</div>
</template>
<script>
methods: {
changeThisPic(row) {
this.editPic = true;
this.editData.testId = row.testId;
this.editData.testItemId = row.testItemId;
},
sendPicForUpdate() {
this.$store
.dispatch("UPDATE_PIC", {
testId: this.editData.testId,
uploadFile: this.editData.uploadFile,
testItemId: this.editData.testItemId
})
}
</script>
export default function (/* { ssrContext } */) {
const Store = new Vuex.Store({
mutations: {
UPDATE_PIC ({ commit }, payload) {
const formData2 = new FormData()
Object.entries(payload).forEach(([key, val]) => {
formData2.append(key, val)
})
axios
.put('http://localhost/MyComposer/', formData2, {
params: {
updateId: 2,
testId: payload.testId,
testItemId: payload.testItemId
}
})
.then(response => {
alert(response.data)
console.log(response)
})
.catch(error => {
console.log(error)
})
}
},
Backend
<?php
if (isset($_GET['updateId']) && $_GET['updateId'] == 1) {
$data = file_get_contents('php://input');
$decoded = json_decode($data);
$testId = $decoded->{'testId'};
$sub = $decoded->{'subject'};
$question = $decoded->{'question'};
$answer = $decoded->{'answer'};
$testItem = $decoded->{'testItemId'};
$db->where('TestItemId', $testItem);
$arrayDir = array('FileLocation');
$uploaddir = $db->get('teachertest', null, $arrayDir);
$uploadfile = $uploaddir . $_FILES['uploadFile']['name'];
if (move_uploaded_file($_FILES['uploadFile']['tmp_name'], $uploadfile)) {
echo "File is valid, and was successfully uploaded.\n";
} else {
echo "Upload failed";
}
if (!empty($sub)) {
$sdata = array(
'SubjectId' => $sub,
);
$db->where('TestId', $testId);
$newsub = $db->update('teachertest', $sdata);
if ($newsub) {
echo "Subject was changed and";
}
$tdata = array(
'Question' => $question,
'Answer' => $answer,
);
$db->where('TestId', $testId);
$newdb = $db->update('testdetails', $tdata);
if ($newdb) {
echo "Test item details were updated!";
}
}
?>
Related
i am trying to update a data through axio as showing below:
<b-form #submit.prevent="update" enctype="multipart/form-data">
.
.
.
.
<b-form-file
v-model="invoice.file"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
v-on:change="onChange"
/>
Script:
data() {
return {
invoice: {
.
.
.
file: "",
_method: "patch"
}
};
},
methods: {
onChange(e) {
this.file = e.target.files[0];
},
async update() {
await this.axios
.post(`/api/auth/outstanding-payment/${this.$route.params.id}`, this.invoice)
.then((response) => {
this.$router.push({ name: "apps-invoice-list" });
})
.catch((error) => {
console.log(error);
});
},
controller for the update function:
public function update(Request $request, OutstandingPayment $outstandingPayment)
{
$payment_voucher_supporting_doc = '';
if ($request->hasFile('file')) {
$payment_voucher_supporting_doc = time() . '.' . $request->file->extension();
$request->file->storeAs('uploads/images/test', $payment_voucher_supporting_doc);
if ($outstandingPayment->payment_voucher_supporting_doc) {
Storage::delete('public/images/' . $outstandingPayment->payment_voucher_supporting_doc);
}
}
else {
$payment_voucher_supporting_doc = $outstandingPayment->payment_voucher_supporting_doc;
}
$postData = [
'payment_voucher_file_ref_no' => $request->payment_voucher_file_ref_no,
'payment_voucher_date' => $request->payment_voucher_date,
.
.
.
'payment_voucher_received_by' => $request->payment_voucher_received_by,
'payment_voucher_supporting_doc' => $payment_voucher_supporting_doc,
];
$outstandingPayment->update($postData);
}
so when i submit the form all the data will be updated but the file won't be updated
i included "enctype="multipart/form-data"" in the form and checked if the file is passed through the request am i missing something?
UPDATE:
i tried modifying the controller function as below:
if(!$request->file()) {
return response()->json("Hi!");
}
to check if there is no file been passed and i got the response
why the file not being passed in the request?
You're updating wrong value.
Change this
onChange(e) {
this.file = e.target.files[0];
},
To
onChange(e) {
this.invoice.file = e.target.files[0];
},
ANSWER:
i had to use:
_method: "patch"
with FormData:
data.append('_method', this.invoice._method);
The issue is with the div tag with class log, I am trying to populate the text with data gotten from the api response. As I try to include the v-for directive ,the whole div disappears from the browser and there is no single error thrown by the console.
<template>
<div>
<div class="log" v-for="info in infos" v-bind:key="info" v-text="info.login">
Username
</div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
name: '',
infos: null,
}
},
methods: {
hello() {
let user = document.querySelector(".search").value;
let fullname = user.split(" ").join("");
let msg = "No Username Found";
const axios = require("axios");
axios.get("https://api.github.com/users/" + fullname)
.then(response => (this.infos = response.data))
.catch(error => alert(error + " " + msg))
},
reset() {
this.name = "";
}
}
};
</script>
infos is null so the div will not show.
Below i've added a created function, where I call hello().This will populate infos and show the div.
<script>
export default {
name: "HelloWorld",
data() {
return {
name: '',
infos: null,
}
},
created() {
hello();
},
methods: {
hello() {
let user = document.querySelector(".search").value;
let fullname = user.split(" ").join("");
let msg = "No Username Found";
const axios = require("axios");
axios.get("https://api.github.com/users/" + fullname)
.then(response => (this.infos = response.data))
.catch(error => alert(error + " " + msg))
},
reset() {
this.name = "";
}
}
};
</script>
try using computed method
<template>
<div>
<div class="log" v-for="info in infosComputed" v-bind:key="info" v-text="info.login">
Username
</div>
</div>
</template>
...
computed {
infosComputed: function() {
return this.infos;
}
}
data is not reactive
I am trying to pass below data to the laravel backend:
form: new Form( {
name: '',
file2: null,
licenses: [
{name: '', xerox: null},
{name: '', xerox: null},
]
}),
I am facing laravel validation problem. Like, if I tried to send data with the help of FormData() then php received the array and can validate the data except array element (i.e. Licenses) which also contains the attached files in an array of objects.
On backend side, it receives like below image. It doesn’t shows attached licenses images, except the profile image.
Below are the codes details also includes the repo of the project, if it needed.
Could you please tell me how could I sent the data with the attachment to the server?
Example-component.vue
<template>
<b-form #submit.prevent="onSubmit" #keydown="form.errors.clear($event.target.name)">
<b-form-group id="input-group-2" label="Your Name:" label-for="input-2">
<b-form-input
id="input-2"
v-model="form.name"
placeholder="Enter name"
></b-form-input>
</b-form-group>
<input type="file" id="file" ref="file" v-on:change="handleFileUpload()" class="mb-3"/>
<!--License-->
<b-form-group label="License details(if applicable):" class="">
<b-form-group v-for="(l, index) in form.licenses" :key="l.index" align-v="center" class="">
<b-card bg-variant="light">
<b-form-group>
<b-form-input id="input-license1" v-model="l.name" placeholder="Enter your License name:" class=""></b-form-input>
</b-form-group>
<b-form-group>
<input
type="file"
id="filelicense"
name="xerox"
ref="licenseFile"
v-on:change="handleLicenseFileUpload($event.target.name, $event.target.files[0], index)"
class="mb-3"/>
<div>Selected file: {{ l.xerox ? l.xerox.name : '' }}</div>
</b-form-group>
</b-card>
</b-form-group>
</b-form-group>
<b-button type="submit" variant="primary">Submit</b-button>
</b-form>
</template>
<script>
import Form from "../core/Form";
export default {
data() {
return {
form: new Form( {
name: '',
file2: null,
licenses: [
{name: '', xerox: null},
{name: '', xerox: null},
]
}),
isLoading: false
}
},
methods: {
handleLicenseFileUpload(fieldName, SelectedFile, index) {
console.log(SelectedFile);
this.form.licenses[index].xerox = SelectedFile;
},
onSubmit() {
this.isLoading = true;
this.form.post('/candidates')
.then(response => {
this.response = response
console.log(response.data.message)
})
.catch((err) => {
})
.finally(() => {
this.isLoading = false
})
},
handleFileUpload(){
this.form.file2 = this.$refs.file.files[0];
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
CandidateController.php
public function store(Request $request)
{
$data = $request->validate([
'name' => 'required',
'file2' => '',
'licenses.*.name' => 'required',
'licenses.*.xerox' => 'required',
]);
dd($request->all());
Form.js
courtesy
import Errors from './Errors';
class Form {
constructor(data) {
this.originalData = data;
for (let field in data) {
this[field] = data[field];
}
this.errors = new Errors();
}
data() {
let data = {};
for (let property in this.originalData) {
data[property] = this[property];
}
return data;
}
setFormData(data) {
let formData = new FormData();
for (let field in data) {
formData.append(field, data[field]);
}
return formData;
}
reset() {
for (let field in this.originalData) {
this[field] = '';
}
this.errors.clear();
}
post(url) {
return this.submit('post', url);
}
submit(requestType, url) {
let config = {
headers: {
Authorization: 'sometoken',
'Content-Type': `multipart/form-data; boundary=${Math.random().toString().substr(2)}`,
}
}
return new Promise((resolve, reject) => {
axios[requestType](url, this.setFormData(this.data()))
.then(response => {
this.onSuccess(response.data);
resolve(response.data);
})
.catch(error => {
this.onFail(error.response.data.errors);
reject(error.response.data);
});
});
}
onSuccess(data) {
//alert(data.message); // temporary
this.reset();
}
onFail(errors) {
this.errors.record(errors);
}
}
export default Form;
I'm following this tutorial I found on the web and I've installed the dependency correctly. But i'm not able to upload my file to the server
JS
imageChangedEvent: any = '';
croppedImage: any = '';
fileChangeEvent(event: any): void {
this.imageChangedEvent = event;
}
imageCropped(event: ImageCroppedEvent) {
this.croppedImage = event.base64;
const formData = new FormData();
formData.append('file', this.croppedImage);
this.http.post(this.global.baseUrl + upload.php', formData, {
}).subscribe(data => {
console.log(JSON.stringify(data));
// this.newfileName = (data);
this.loader = false;
});
}
imageLoaded() {
// show cropper
}
loadImageFailed() {
// show message
}
HTML
<image-cropper
[imageChangedEvent]="imageChangedEvent"
[maintainAspectRatio]="true"
[aspectRatio]="4 / 4"
[resizeToWidth]="128"
format="png"
(imageCropped)="imageCropped($event)"
(imageLoaded)="imageLoaded()"
(loadImageFailed)="loadImageFailed()"
></image-cropper>
PHP
$path = '../upload_imgs/';
if (isset($_FILES['file'])) {
$originalName = $_FILES['file']['name'];
$ext = '.'.pathinfo($originalName, PATHINFO_EXTENSION);
$generatedName = md5($_FILES['file']['tmp_name']).$ext;
$filePath = $path.$generatedName;
$photo=array("generatedName"=>($generatedName));
if (!is_writable($path)) {
echo json_encode(array(
'status' => false,
'msg' => 'Destination directory not writable.'
));
exit;
}
if (move_uploaded_file($_FILES['file']['tmp_name'], $filePath)) {
echo json_encode(array($photo));
}
}
else {
echo json_encode(
array('status' => false, 'msg' => 'No file uploaded.')
);
exit;
}
After cropping the console reads nothing. is there something i may be doing wrong?
Isn't an apostroph missing here:
this.http.post(this.global.baseUrl + upload.php', formData, {
I have chat message system.
I have code:
<template>
<li :class="className">
{{ message }}
</li>
</template>
<script>
export default {
props: [
'message',
'user',
'time',
'seen',
],
computed: {
className() {
return this.seen;
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
App.js:
data:{
message: '',
convId: 1,
chat: {
message: [],
user: [],
time: [],
seen: [],
},
typing: '',
},
....
watch: {
message() {
Echo.private('chat')
.whisper('typing', {
name: this.message
});
}
},
methods: {
send(){
if(this.message.length != 0 && this.message.length <= 4000) {
this.chat.message.push(this.message);
this.chat.user.push('you');
this.chat.time.push(this.getTime());
this.chat.seen.push('unread'). //set class unread message for user
axios.post('/sendMessage', {
message: this.message,
//lastName: 'Flintstone'
})
.then(response => {
console.log(response);
this.message = '';
})
.catch(error => {
console.log(error);
});
}
},
seenMessage() {
axios.post('/setMessagesSeen/' + this.convId) //this request mark messages in chat all readed for auhenticated user
.then( response => { this.chat.seen.push(''); //remove unread class })
.catch( response => { console.log(response) } )
},
getTime() {
let time = new Date();
return time.getHours() + ':' + time.getMinutes();
}
},
mounted() {
Echo.private('chat')
.listen('ChatEvent', (e) => {
this.chat.message.push(e.message);
this.chat.user.push(e.user);
this.chat.time.push(this.getTime());
this.chat.seen.push('unread'). //set class unread message for user
console.log(e);
})
.listenForWhisper('typing', (e) => {
if(e.name != '')
this.typing = 'typing..';
else
this.typing = null;
});
}
My chat.blade.php:
<message v-for="value,index in chat.message"
:key=value.index
:user=chat.user[index]
:message="chat.message[index]"
:time="chat.time[index]"
:seen="chat.seen[index]"
>
</message>
<div class="form-group">
<textarea maxlength="4000" cols="80" rows="3" class="message-input form-control" v-model='message' v-on:click="seenMessage"></textarea>
</div>
<div class="form-group">
<button type="button" class="btn btn-lg btn-primary" v-on:click="send">Send message</button>
</div>
My function seen:
public function setMessagesSeen(Conversation $conversation) {
$user = User::find(Auth::id());
$conversations = Chat::conversation($conversation->id);
//$dd = Chat::conversations($conversation)->for($user)->readAll();
dd(Chat::conversations($conversations)->for($user)->getMessages()->where('body', 'asdfsadfsd'));
//$message = Chat::messages($message)->for($user)->markRead();
broadcast(new HasSeenMessage($message));
return response('ok');
}
How I can send class "unread" to element div other user? I can paste class on current user, and I get color on element chat only for me, but how I can hide element for me and other user, when message is seen?
I want do read/unread function for users.
Example:
If user in real time send message I send class unread, when other user click on textarea, I remove class unread, and said user, that message is seen. How I can do it in real time add/remove class unread? My function is not working.
To do this you have to create an Event in your Laravel application that you will broadcast on a precise channel (you can for example give the name 'chat. {Conversation}. {User_id}') and with Laravel Echo you will listen this event!
I allowed myself to make some changes in your code -:)
I presume you have this class HasSeenEvent
<?php
namespace App\Events;
use App\Order;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class HasSeenEvent implements ShouldBroadcast
{
use SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #param Message $message
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
public function broadcastOn()
{
// I presume we can get conversation id like this : $this->message->conversation->id
return new PrivateChannel('chat.'.$this->message->conversation->id.'.'.$this->message->sender->id);
}
}
Then, in your routes/broadcast.php declare this route chat.{conversation}.{user_id}
In the function where you put the 'seen' to 1 you broadcast the event at the same time
broadcast(new HasSeenMessage($message))
Then you listen to this event in your vuejs code
components/Message.js
<template>
<li :class="className">
{{ message }}
</li>
</template>
<script>
export default {
props: [
'message',
'user',
'time',
'readed',
],
computed: {
className() {
return this.readed == 1 ? 'seen' : 'unread';
}
},
mounted() {
console.log('Component mounted.')
}
}
</script>
chat.blade.php
<message v-for="message,index in chat.messages"
:key="index"
:user="message.user"
:message="message.content"
:time="message.time"
:readed="message.readed"
>
</message>
<div class="form-group">
<button type="button" class="btn btn-lg btn-primary" v-on:click="send">Send message</button>
</div>
App.js
data: {
message: '',
convId: 1,
chat: {
messages: [],
/* message: [],
user: [],
time: [],
seen: [], */
},
typing: '',
},
....
watch: {
message() {
Echo.private('chat')
.whisper('typing', {
name: this.message
});
}
},
methods: {
send() {
if (this.message.length != 0 && this.message.length <= 4000) {
let data = {
content: this.message,
user: 'you',
time:this.getTime(),
readed: 0
}
this.chat.messages.push(data)
data = {}
axios.post('/sendMessage', {
message: this.message,
//lastName: 'Flintstone'
})
.then(response => {
console.log(response);
this.message = '';
})
.catch(error => {
console.log(error);
});
}
},
seenMessage() {
axios.post('/setMessagesSeen/' + this.convId) //this request mark messages in chat all readed for auhenticated user
.then(response => {
//This is not the best way to do that
this.chat.messages[this.messages.length -1 ].readed = 0
}).catch(response => {
console.log(response)
})
},
getTime() {
let time = new Date();
return time.getHours() + ':' + time.getMinutes();
}
},
mounted() {
Echo.private('chat')
.listen('ChatEvent', (e) => {
this.chat.messages.push({
content: e.message,
user: e.user,
time: this.getTime(),
readed: 0
})
console.log(e);
})
.listenForWhisper('typing', (e) => {
if (e.name != '')
this.typing = 'typing..';
else
this.typing = null;
});
// I presume to can access to user info
let that = this
Echo.private('chat.'+convId+'.'+user.id)
.listen('HasSeenMessage', (e) => {
let message = e.message
let lookingForMessage = that.chat.messages.find((m) => {
// I presume in your db messages table has field content and time
return m.content == message.content && m.time => message.time
})
try {
lookingForMessage.readed = 1
}catch (err){
// message not found
console.log(err)
}
})
}
Hope it helped you!