We are using Vue in our frontend application, and for one of our REST service our backend server(using spring and java) expects to have the below data structure:
public class MAProductsUploadRequest
{
public List<MAProductUploadRequest> products;
}
public class MAProductUploadRequest {
public String productName;
public String productDescription;
public double productPrice;
public int productOrder;
public MultipartFile productImage=null;
public double cropX;
public double cropY;
public double cropWidth;
public double cropHeight;
public int categoryId;
}
And in our Vuejs application we tried to post the data as in the below code:
addProducts: function () {
console.log("Add Products Working. Total Product Count:"+this.excelProducts.length);
let header = {
headers: auth.getAuthHeader()
};
let formData = new FormData();
for (let i=0;i<this.excelProducts.length;i++ ) {
console.log("Starting loop:"+i);
var prod = this.excelProducts[i];
console.log("Product Before:"+prod);
if (document.getElementById('photo-image-'+i) !== null) {
if(document.getElementById('photo-image-'+i).files.length !== 0) {
console.log("Getting Image For Prod");
prod.productImage = document.getElementById('photo-image-'+i).files[0] ;
}
}
prod.cropX = this.cropProp.x;
prod.cropY = this.cropProp.y;
prod.cropWidth = this.cropProp.width;
prod.cropHeight = this.cropProp.height;
prod.rotate = this.cropProp.rotate;
console.log("Product After:"+prod);
formData.append("products[]",prod);
}
for (var pair of formData.entries()) {
console.log(pair[0]+ ', ' + pair[1]);
}
//console.log("Form Data:"+formData.products);
if (formData.products !== null) {
axios.post(`${API_URL}/company/uploadProducts`, formData, header).then((response) => {
logForDevelopment(response);
this.getProducts();
this.product = {
id: '',
name: '',
description: '',
price: '',
photo: '',
isEdit: false
};
this.excelProducts = [];
this.isPhotoChosen = false;
this.isPhotosChosen = [];
this.cropImg = '';
document.getElementById('photo-image').value = null;
this.isLoading = false;
}).catch((error) => {
this.isLoading = false;
if(error.response) {
logForDevelopment(error);
document.getElementById('photo-image').value = null;
if(error.response.status === 401 || error.response.status === 403) {
auth.afterInvalidToken('login');
}
}
})
} else {
console.log("Form Data Is Empty");
}
},
But when we use this code (even if the photo-image was null) the backend server returns HTTP 500 error. Because the products array seems null.
I wasn't able to figure it out where the problem may be in the Vuejs code?
EDIT: (I'VE also tried the below code but the still same result)
addProducts: function () {
console.log("Add Products Working. Total Product Count:"+this.excelProducts.length);
let header = {
headers: auth.getAuthHeader()
};
let formData = new FormData();
let prods = [];
for (let i=0;i<this.excelProducts.length;i++ ) {
console.log("Starting loop:"+i);
let prod = this.excelProducts[i];
let subFormData = new FormData();
subFormData.append("productName",prod.productName);
subFormData.append("productDescription",prod.productDescription);
subFormData.append("productPrice",prod.price);
subFormData.append("categoryId",prod.categoryId);
subFormData.append("cropX",this.cropProp.x);
subFormData.append("cropY",this.cropProp.y);
subFormData.append("cropWidth",this.cropProp.width);
subFormData.append("cropHeight",this.cropProp.height);
prods.push(subFormData);
if (document.getElementById('photo-image-'+i) !== null) {
if(document.getElementById('photo-image-'+i).files.length !== 0) {
console.log("Getting Image For Prod");
subFormData.productImage = document.getElementById('photo-image-'+i).files[0] ;
}
}
}
formData.append("products",prods);
console.log("Form Data:"+formData);
if (formData.products !== null) {
axios.post(`${API_URL}/company/uploadProducts`, formData, header).then((response) => {
logForDevelopment(response);
this.getProducts();
this.product = {
id: '',
name: '',
description: '',
price: '',
photo: '',
isEdit: false
};
this.excelProducts = [];
this.isPhotoChosen = false;
this.isPhotosChosen = [];
this.cropImg = '';
document.getElementById('photo-image').value = null;
this.isLoading = false;
}).catch((error) => {
this.isLoading = false;
if(error.response) {
logForDevelopment(error);
//document.getElementById('photo-image').value = null;
if(error.response.status === 401 || error.response.status === 403) {
auth.afterInvalidToken('login');
}
}
})
} else {
console.log("Form Data Is Empty");
}
},
What I'm actually trying to achive is, our below code works fine when sending single product info to our backend service, but I want to make it an array so send multiple products at once:
addProduct: function () {
let header = {
headers: auth.getAuthHeader()
};
let formData = new FormData();
formData.append('productName', this.product.name);
formData.append('productDescription', this.product.description === '' ? "" : this.product.description);
formData.append('productPrice', this.product.price);
formData.append('categoryId', this.product.categoryId);
if(document.getElementById('photo-image').files.length !== 0) {
formData.append('productImage', document.getElementById('photo-image').files[0]);
}
formData.append('cropX', this.cropProp.x);
formData.append('cropY', this.cropProp.y);
formData.append('cropWidth', this.cropProp.width);
formData.append('cropHeight', this.cropProp.height);
formData.append('rotate', this.cropProp.rotate);
console.log(formData);
axios.post(`${API_URL}/company/products`, formData, header).then((response) => {
logForDevelopment(response);
this.getProducts();
this.product = {
id: '',
name: '',
description: '',
price: '',
photo: '',
isEdit: false
};
this.isPhotoChosen = false;
this.cropImg = '';
document.getElementById('photo-image').value = null;
this.isLoading = false;
}).catch((error) => {
this.isLoading = false;
if(error.response) {
logForDevelopment(error);
document.getElementById('photo-image').value = null;
if(error.response.status === 401 || error.response.status === 403) {
auth.afterInvalidToken('login');
}
}
})
},
Does anyone have any idea about that?
You can also look at the screenshot of my application in below(I want to send all the items in screenshot , at once )
Your issue is probably il the formData.append("products[]",prod) method of your FormData class, try changing formData.append("products[]",prod) with formData.products.push(prod).
Furthermore in your axios call the payload should be formData.products if you API endpoint expects the products right?
Try axios.post(${API_URL}/company/uploadProducts, formData.products, header).
I do not see any syntax issue relative to Vue, hope this helps. (And of course check what is sent by XHR in devtools as suggested in the comments)
Related
Use this function to flatten the response returned from strapi on version 4. Helps you get rid of data and attributes properties
This will give you the same response structure as version 3 of strapi. This would help you migrate to version 4 from version 3 easily.
How to use it?
import the file.
const flattnedData = flattenObj({...data})
NOTE: The data here is the response returned from strapi version 4.
export const flattenObj = (data) => {
const isObject = (data) =>
Object.prototype.toString.call(data) === "[object Object]";
const isArray = (data) =>
Object.prototype.toString.call(data) === "[object Array]";
const flatten = (data) => {
if (!data.attributes) return data;
return {
id: data.id,
...data.attributes,
};
};
if (isArray(data)) {
return data.map((item) => flattenObj(item));
}
if (isObject(data)) {
if (isArray(data.data)) {
data = [...data.data];
} else if (isObject(data.data)) {
data = flatten({ ...data.data });
} else if (data.data === null) {
data = null;
} else {
data = flatten(data);
}
for (const key in data) {
data[key] = flattenObj(data[key]);
}
return data;
}
return data;
};
In my case I created a new middleware "flatten-response.js" in "middlewares" folder.
function flattenArray(obj) {
return obj.map(e => flatten(e));
}
function flattenData(obj) {
return flatten(obj.data);
}
function flattenAttrs(obj) {
let attrs = {};
for (var key in obj.attributes) {
attrs[key] = flatten(obj.attributes[key]);
}
return {
id: obj.id,
...attrs
};
}
function flatten(obj) {
if(Array.isArray(obj)) {
return flattenArray(obj);
}
if(obj && obj.data) {
return flattenData(obj);
}
if(obj && obj.attributes) {
return flattenAttrs(obj);
}
for (var k in obj) {
if(typeof obj[k] == "object") {
obj[k] = flatten(obj[k]);
}
}
return obj;
}
async function respond(ctx, next) {
await next();
if (!ctx.url.startsWith('/api')) {
return;
}
ctx.response.body = flatten(ctx.response.body.data)
}
module.exports = () => respond;
And I called it in "config/middlewares.js"
module.exports = [
/* ... Strapi middlewares */
'global::flatten-response' // <- your middleware,
'strapi::favicon',
'strapi::public',
];
Backend is Laravel and Firebase, frontend is React Native.
I tried to upload image to server on app, it is working well on emulator, but on real device.
Actually on real device when I click the upload button, the image saves to the MySQL DB correctly, but it doesn't navigate to the next page and I can't get any response. (On emulator, all works fine.)
Following is my uploading code.(react-native)
import { url } from "../config/config";
const link = "/personal_info";
export default class Personal extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
national_id: "",
email: "",
country: "US",
address: "",
company: "",
job_title: "CEO",
user_id: "",
front_image: {},
back_image: {},
front_image_upload: '',
back_image_upload: '',
};
}
SavePersonal = () => {
var myobj = this;
var apiUrl = url + link;
console.log("api is ", apiUrl);
fetch(apiUrl, {
method: "post",
body: JSON.stringify(this.state),
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
}).then(function (response) {
console.log('response->', response); //--- I can't get this response.
response.json().then(function (resp) {
console.log('resp->', resp); //--- I can't get this resp.
if (resp == 0) { //--- But image saves well in MySQL DB.
Alert.alert(
"Something Went Wrong",
"Please Make Sure You Fill All Fields."
);
} else if (resp == 1) {
console.log('success->', resp);
myobj.props.navigation.push("Work");
}
});
}).catch((error) => {
console.log('personal_info_error', error);
})
};
render() {
return (
....... ........ ........
<View style={{ ...styles.margin_btm, marginTop: 20 }}>
<Button
onPress={() => {
this.SavePersonal();
}}
mode="contained"
>
Continue
</Button>
</View>
)
}
}
That is Laravel backend code.
<?php
namespace App\Http\Controllers;
use App\Personal;
use Illuminate\Http\Request;
class PersonalController extends Controller
{
function personal_info(Request $request)
{
$img = $request->front_image_upload;
// $img = explode(',', $request->front_image_upload);
$file = base64_decode($img);
$folderName = 'public/uploads/';
$safeName = uniqid().'.'.'png';
$destinationPath = public_path() . $folderName;
$success = file_put_contents(public_path().'/uploads/'.$safeName, $file);
$front_img = 'uploads/'.$safeName;
$img2 = $request->back_image_upload;
// $img2 = explode(',', $request->back_image_upload);
$file2 = base64_decode($img2);
$folderName2 = 'public/uploads/';
$safeName2 = uniqid().'.'.'png';
$destinationPath2 = public_path() . $folderName2;
$success = file_put_contents(public_path().'/uploads/'.$safeName2, $file2);
$back_img = 'uploads/'.$safeName2;
$personal = new Personal;
$personal->user_id = $request->user_id;
$personal->name = $request->name;
$personal->address = $request->address;
$personal->company = $request->company;
$personal->country = $request->country;
$personal->email = $request->email;
$personal->job_title = $request->job_title;
$personal->national_id = $request->national_id;
$personal->front_img = $front_img;
$personal->back_img = $back_img;
$personal->save();
if($personal)
{
$code = 1;
}
else
{
$code = 0;
}
return $code;
}
}
Try this. You have a problem with the .then().then().catch() grammar.
SavePersonal = () => {
// var myobj = this;
var apiUrl = url + link;
console.log("api is ", apiUrl);
fetch(apiUrl, {
method: "post",
body: JSON.stringify(this.state),
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((resp) => {
console.log('---', resp);
if (resp == 0) {
Alert.alert(
"Something Went Wrong",
"Please Make Sure You Fill All Fields."
);
} else if (resp == 1) {
console.log('success = ', resp);
this.props.navigation.push("Work");
}
})
.catch((error) => {
console.log('personal_info_error', error);
})
};
you can try to pass the url in another way, instead of:
import {url} from "../config/config"
use
import {url} from "/ config / config"
export class AddCategory extends Component {
state = {
categoryForm: {
category: {
elementType: 'input',
elementConfig: {
type: 'text',
placeholder: 'Enter Category'
},
value: '',
validation: {
required: true
},
valid: false,
touched: false
}
}
};
checkValidity(value, rules) {
let isValid = true;
if (!rules) {
return true;
}
if (rules.required) {
isValid = value.trim() !== '' && isValid;
}
return isValid;
}
inputChangedHandeller = (event, controlNameOne) => {
const copyLoginFrom = {
...this.state.categoryForm,
};
const newCopy = {
...copyLoginFrom[controlNameOne]
};
newCopy.value = event.target.value;
newCopy.valid = this.checkValidity(newCopy.value, newCopy.validation);
newCopy.touched = true;
copyLoginFrom[controlNameOne] = newCopy;
let formIsValid = true;
for (let inputIdentifier in copyLoginFrom) {
formIsValid = copyLoginFrom[inputIdentifier].valid && formIsValid;
}
this.setState({
categoryForm: copyLoginFrom,
formIsValid: formIsValid
});
}
dataPost = (event) => {
event.preventDefault();
const formData = {};
for (let addressData in this.state.categoryForm) {
formData[addressData] = this.state.categoryForm[addressData].value;
}
const newAddress = {
newAddressData: formData
}
console.log("Hello......." + newAddress);
const parentId = this.state.parent_id;
const options = {
method: 'POST',
headers: {
Authorization: "Bearer " + localStorage.getItem("token")
},
data: formData,
url: 'http://localhost:8080/admin/category/'
}
axios(options);
}
render() {
const formElementsArray = []; //converting state object to the array I can loop throuh
for (let key in this.state.categoryForm) {
formElementsArray.push({
id: key,
config: this.state.categoryForm[key]
});
}
let form = ( <
form onSubmit = {
this.dataPost
} > {
formElementsArray.map(forElement => ( <
Input key = {
forElement.id
}
elementType = {
forElement.config.elementType
}
elementConfig = {
forElement.config.elementConfig
}
value = {
forElement.config.value
}
invalid = {
!forElement.config.valid
}
shouldValidate = {
forElement.config.validation
}
touched = {
forElement.config.touched
}
elementGet = {
(event) => this.inputChangedHandeller(event, forElement.id)
}
/>
))
}
<
button className = "btn btn-primary"
disabled = {
!this.state.formIsValid
} > Submit < /button> <
/form>
)
return ( <
div >
<
div className = {
styles.Login
} > {
form
} <
/div> <
/div>
)
}
}
I am trying to send data using axios but the output I am getting in mysql table is Null.Can anyone tell me what is the problem with my code.I tried printing the sent data on console and output I am getting is [object Object] I tried using stringify method but It gives error of header while posting data
try qs which is a query string parser:
npm install qs
and then :
import qs from "qs"
// in your body
const options = {
method: 'POST',
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
'Content-Type': 'application/x-www-form-urlencoded' // need to add content type
},
data: qs.stringify(formData),
url: 'http://localhost:8080/admin/category/'
}
I have a weather API using JSON that works on my local machine, but when I try to deploy it to GithubPages, it nulls out and the API doesn't pull. It was written in js for a reactjs page.
Here is the working site that is on localhost:3000
Not working website hosted on GitHub pages
Deployed Website
state = {
current: 'none'
}
fetchWeather = () => {
return fetch(`https://api.aerisapi.com/observations/75248client_id=${accessId}&client_secret=${APIkey}`)
.then((res) => res.json())
}
componentDidMount = () => {
this.fetchWeather()
.then((json) => {
json.success ? this.setState({ current: json.response.ob }) : null
})
}
formatCurrentWeather = (currentWeather) => {
let current = ''
if (currentWeather.toLowerCase().charAt(currentWeather.length-1) === 'y') {
current = currentWeather.toLowerCase() + ' '
} else if (currentWeather.toLowerCase() === 'clear') {
current = 'cloudless '
} else if (currentWeather.toLowerCase() === 'freezing fog') {
current = 'freezing '
} else if (currentWeather.toLowerCase().charAt(currentWeather.length-1) === 'g') {
current = currentWeather.toLowerCase() + 'gy '
} else {
current = currentWeather.toLowerCase() + 'y '
}
return current
}
importAll = (r) => {
let icons = {};
r.keys().map((item, index) => { icons[item.replace('./', '')] = r(item); });
return icons;
}
render() {
console.log(this.state.current)
const icons = this.importAll(require.context('../images/icons', false, /\.(png|jpe?g|svg)$/));
let currentWeather = '🌃'
this.state.current === 'none' ? null : currentWeather = this.formatCurrentWeather(this.state.current.weatherPrimary)
I had a problem about views on the website, the display will be right when i do somenthing to display, for example, when i type something in the textbox, it will be displayed correctly and when i resize my browser, the appearance will be true also.
This is example when the display is wrong :
and then this is example when the display is right and this is happened after i resize my browser :
my checkbox treeview will show after i resize my browser.
this is my code, mybe the problem in here :
export class AdministrationMenuGroupEditor{
rows = [];
menuList = [];
selectedMenu: any = [];
//id
public id:number;
public statusForm:string;
//form start
public form:FormGroup;
public submitButtonText:string;
public inHTML5 = true;
public name:AbstractControl;
public description:AbstractControl;
public submitted:boolean = false;
constructor(protected service:AdministrationMenuGroupEditorService, private route: ActivatedRoute, private fb:FormBuilder, _ref: ChangeDetectorRef){
this.route.params.subscribe(params => {
this.id = +params['id'];
});
}
ngOnInit(){
this.submitButtonText = 'Save';
this.form = this.fb.group({
'id': [],
'name': ['', Validators.compose([Validators.required,Validators.minLength(3)])],
'description': []
});
this.name = this.form.controls['name'];
this.description = this.form.controls['description'];
this.service.getMenuGroup()
.subscribe(
data => this.setMenuGroup(data['menuGroup']),
err => this.logError(err),
() => this.finishedGetIndexList('Save')
);
this.statusForm = 'Add';
if(this.id){
this.fetchData();
}
}
setMenuGroup(value){
if (value.length > 0){
this.menuList = value;
console.log(this.menuList);
}
}
fetchData(){
this.service.getIndex(this.id)
.subscribe(
data => this.setValueToForms(data['menuGroup']),
err => this.logError(err),
() => this.finishedGetIndexList('Fetch')
);
}
toggleFormControl(formName:string,value:boolean) : void {
let ctrl = this.form.get(formName);
value==false ? ctrl.disable() : ctrl.enable();
ctrl.markAsUntouched();
}
validationDataInput(value){
if(value == 'name invalid'){
console.log('This name was used, please input different name');
return false;
}
return true;
}
setValueToForms(value) : void {
console.log(value);
if(value.length > 0){
if(this.validationDataInput(value)== true){
this.rows = value[0];
if(this.rows['id']){
this.id = this.rows['id'];
}
this.form.setValue({
'id': this.id,
'name': this.rows['name'],
'description': this.rows['description']
});
this.menuList = value[0]['menuList'];
this.selectedMenu = [];
this.statusForm = 'Edit';
}
}
else{
this.statusForm = 'Add';
}
}
onSubmit(values:Object):void{
values['selectedMenu'] = this.selectedMenu;
this.submitted = true;
this.submitButtonText = 'Saving...';
if (this.form.valid) {
this.service.getSave(values,(this.id)?'edit':'new')
.subscribe(
data => this.succeededSave(data['menuGroup']),
err => this.logError(err),
() => this.finishedGetIndexList(' Save'),
);
}
}
finishedGetIndexList(msg){
console.log('Finish '+msg);
this.submitButtonText = 'Save';
this.submitted = false;
}
logError(errMsg){
let errStatus = errMsg['status'];
window.alert('An error has been detected, please reload this page..');
this.submitButtonText = 'Save';
this.submitted = false;
}
succeededSave(result){
this.setValueToForms(result);
}
}
Is there anyone who can help my problem ?