Flutter - Unhandled Exception: NoSuchMethodError: The getter 'filename' was called on null - mongodb

I am still learning flutter and have been facing problems in my project like the error stated in the title. I want to upload files in flutter using dio and formData. The img[] is the variable from the database in mongodb and I am having an error whenever the user passes null image. (Because we do not require the user to send an image.)
Here's my code.
upload2(List<File> babyList) async {
var formData = FormData.fromMap({
"userId": _id,
"babyname": _baby,
});
if(_babyList.length != 0){
for (int i = 0; i < _babyList.length; i++) {
var fileName = babyList[i].path.split('/').last;
formData.files.addAll([
MapEntry(
"babyimage[]",
await MultipartFile.fromFile(babyList[i].path,
filename: fileName,
contentType: new MediaType(lookupMimeType(fileName).split('/')[0], lookupMimeType(fileName).split('/')[1],
))),
]);
}
} else {
formData.files.addAll([ MapEntry("babyimage[]", null)]);
}
// sending the formdata to the database
AuthService().requestorRegister(formData).then((val) async {
print('Form Submitted Successfully');
_confirmationDialog(context);
});
}

Okay, I have tried not to add babyimage[] in the formdata, I have also tried to put empty array, null and babyList as value. The thing is they work and the only problem in my case is the server. The server wasn't updated. So sometimes we gotta check the server too. lol
PS. I removed the else in the code since it is empty.

Related

Showing Error when i try to upload list of images which have Iterable<ImageFile> type

i am using multi_image_picker_view which return Iterable and i Add it into My List images; Like this
onChange: (p0) {
image.add(File(p0.toString()));
},
i want to Upload this Image List to My Server but showing error on image.File[i].path:
FileSystemException (FileSystemException: Cannot retrieve length of file, path = '[Instance of 'ImageFile', Instance of 'ImageFile', Instance of 'ImageFile', Instance of 'ImageFile']' (OS Error: No such file or directory, errno = 2))
i try to print my image List and the result was
[File: '[Instance of 'ImageFile', Instance of 'ImageFile', Instance of 'ImageFile', Instance of 'ImageFile', Instance of 'ImageFile']']
this is my function where i try to send array of my images to my server
uploadsurveryImage(List\<File\> imageFile) async {
var request = http.MultipartRequest('POST', Uri.parse(FORM_URL));
for (var i = 0; i \< imageFile.length; i++) {
request.files.add(http.MultipartFile(
'gallery',
File(imageFile\[i\].path).readAsBytes().asStream(),
// showing error here when reading the length of images
File(imageFile\[i\].path).lengthSync(),
filename: basename(imageFile\[i\].path.split("/").last)));
}
var response = await request.send();
if (response.statusCode == 200) {
return 'done'
} else {
return 'Something Wrong';
}
}
i just want to upload images to my server
When you're doing this: image.add(File(p0.toString())); The .toString method doesn't give you a path, it returns a string that represents the object.
Instead, use the path property from the ImageFile class.
So, this should work:
image.add(File(p0.path));

image picker path for stripe readfilesync Flutter Web

I'm using the file_picker package for flutter https://pub.dev/packages/file_picker
I have read many times that because you can’t access paths on web browsers, you need to use the bytes property, e.g.
FilePickerResult result = await FilePicker.platform.pickFiles();
if(result != null) {
var path = print(result.files.single.path); // this will return null
var bytes = print(result.files.singe.bytes); // this will return a Uint8List of bytes
} else {
// User canceled the picker
}
But I have to upload the images my users select from their devices via the web (so for all types of devices) to my Stripe Connect API in order for them to have a validated identity_document when they register. The bytes Uint8List will throw an error from firebase, here is my code:
export const uploadIdentityFront = async (uid: any, identityFront: any) => {
const fp = fs.readFileSync(identityFront);
const frontIdentity = await stripe.files.create({
file: {
data: fp,
name: 'identityFront.jpg',
type: 'application/octet-stream',
},
purpose: 'identity_document',
});
await updateId(uid, { frontIdentityFileId: frontIdentity.id })
return frontIdentity;
}
The error thrown:
[firebase_functions/unknown] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Array
I will need to send stripe an image document via the file system's readFileSync property in order to do this, but with Flutter Web not being able to print the path for the image chosen by the user, I am stuck on how to resolve this issue
I use this code to send bytes to my server, which uses stream to send. You can use http package to send streams.
var request = http.MultipartRequest(
'POST',
Uri.parse('_url'),
);
request.files.add(
http.MultipartFile.fromBytes(
'identityFront', //name of field which you receive in api
bytes, // bytes
filename: 'identityFront.jpg', // optional name
//contentType: content, optional media Type
));
request.fields.addEntries([
MapEntry('uid', 'uid_value_in_String_Type'),
]);
await request.send();
I finally solved it. For anyone trying to upload a file to Stripe via flutter web, don't create a fs.readFileSync in your backend server side code. Instead, remove it and upload a file like this:
export const uploadIdentityFront = async (uid: any, identityFront: any) => {
const frontIdentity = await stripe.files.create({
file: {
data: identityFront,
name: 'identityFront.jpg',
type: 'image/jpg',
},
purpose: 'identity_document',
});
await updateId(uid, { frontIdentityFileId: frontIdentity.id })
return frontIdentity;
}
This way, you can upload the file via the file_picker package and uploading it as a picker.file.first.bytes. But don't wrap it in a string - send it just like this as a callable function in firebase functions:
await uploadFrontPassport.call(
<dynamic, dynamic>{'identityFront':picked.files.first.bytes}
);

Problem using FormData and MultiFormData for send Files Images in Flutter with Dio

has anyone had this error using Dio and sending 'MultiPart FormData'?
FormData formData = FormData.fromMap({
"target_value": listaDados[0],
"number_installments": listaDados[1],
"installments_frequency": listaDados[2],
"modality": listaDados[3],
"gross_billing": listaDados[4],
"hectare_cost": listaDados[5],
"files": [
MultipartFile.fromFile("${listaDados[6]}",
filename: "Foto_Identidade"),
MultipartFile.fromFile("${listaDados[7]}",
filename: "Foto_Imposto.jpg"),
MultipartFile.fromFile("${listaDados[8]}",
filename: "Selfie_Autorizacao.jpg"),
]
});
//dio.options.baseUrl = "${global.CONEXAO}";
dio.interceptors.add(LogInterceptor());
response = await dio.post("${global.CONEXAO}/credits",
data: await formData,
options: Options(headers: {
'Authorization':
'Bearer $token'
}));
print(response.data);
When I send it like this, it gives status 200, sends all the data, but the files are [] ....
If I put await before MultiPart.fromfile, it gives error 500 and a list of [MapEntry (files []: Instance of 'MultipartFile'), MapEntry (files []: Instance of 'MultipartFile'), MapEntry (files [ ]: Instance of 'MultipartFile')] ...
These photos are taken with the imagePicker and saved in a stream!
There really is a file, I print the list beforehand and show the path and name of the file!
Does anyone know what I can do? Thanks
I got the same problem today,because the map get same key in the backend,so I can not get all the file finally,so I change the souce code as below:
FormData.fromMap(Map<String, dynamic> map) {
_init();
encodeMap(
map,
(key, value) {
if (value == null) return null;
if (value is MultipartFile) {
files.add(MapEntry( value.filename, value)); //here is what I changed
} else {
fields.add(MapEntry(key, value.toString()));
}
return null;
},
encode: false,
);
}
when I change the source code and rebuild my app, everything works fine and I can use the filename as key.
If you dive into the encodeMap source code,you will find out that dio use a recursion to get all the key,value of the entries
but when come to MultipartFile in List ,the Entrance of this recursion is urlEncode(data, ''); the path is empty,and finally we get something like '$path$leftBracket${(sub[i] is Map || sub[i] is List) ? i : ''}$rightBracket'); , that turn out to be something like this
ImmutableMultiDict([('files[]', <FileStorage: 'image_picker677442617592930907_compressed1516097521471936562.jpg' ('application/octet-stream')>), ('files[]', <FileStorage: 'image_picker5187767999094318232_compressed6097930966098340000.jpg' ('application/octet-stream')>)])

display single record by id with vue js and axios

I have a mongodb express vue js app that displays a list of items in cards which are links to a detail view of each record. If I hover over the card the correct id for the link displays but click any card and it goes to the first document from mongo and the record does not display. The view retrieves an item but always the first one.
How to display a record of the ID of item clicked?
Report.vue
the backend request which works in postman is
// Get Simgle Report
router.get('/:id', async (req, res) => {
const reports = await loadReportsCollection()
await reports.findOne({_id: new mongodb.ObjectID( req.params.id)})
res.send(await reports.find({}).limit(1).toArray())
res.status(200).send()
}
)
ReportService.js looks like
//Find Single Report
static getReport(id) {
return axios.get(`${url}${id}`)
}
and the Report.vue file looks like
mounted () {
this.getReport()
},
methods: {
async getReport() {
try {
const response = await ReportService.getReport(this.$route.params.id)
this.report = response.data
} catch(err) {
this.err = err.message
}
},
}
many thanks for help!
It would seem you are trying to access a param in your api without passing one in your request. You ask for params here:
await reports.findOne({_id: new mongodb.ObjectID( req.params.id)})
but haven't passed any in your request. This should do it:
return axios.get('/:id', {
params: {
id: `${id}`
}
})
To not only get the first entry, but the one you are looking for you need to change your send() parameter.
Here is the working code:
// Get Simgle Report
router.get('/:id', async (req, res) => {
const reports = await loadReportsCollection()
const report = await reports.findOne({_id: new mongodb.ObjectID(req.params.id)})
res.send(await report)
res.status(200).send()
}
)
And as Andrew1325 stated you need to change your axios.get() call also to pass the correct params to it.

Using Restangular, can I use a jsonResultsAdapterProvider when needing to override the id field?

I've got a mySql db with non-standard IDs and field names, so I was trying to use both jsonResultsAdapterProvider and setRestangularFields. Here's the code in my app.config file:
RestangularProvider.setBaseUrl(remoteServiceName);
RestangularProvider.setRestangularFields({id: 'personID'});
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
if (data.error) {
return data.error;
}
var extractedData = data.result;
return jsonResultsAdapterProvider.$get().camelizeKeys(extractedData);
});
RestangularProvider.addRequestInterceptor(function(elem, operation, what, url) {
return jsonResultsAdapterProvider.$get().decamelizeKeys(elem);
});
It's all good until I try to do a put/save. When I look at the request payload within the browser dev tools, it's: {"undefined":12842} (but the url is correct, so I know the id is set) If I don't use the ResultsAdapter and change the id field to Person_ID, payload looks good, so I know I'm making the right calls to Get and Save the Restangular objects. But for what it's worth, here's the code:
$scope.tests = Restangular.all('members').getList().$object;
vm.testEdit = function () {
$scope.test = Restangular.one('members', 12842).get().then(function(test) {
var copy = Restangular.copy(test);
copy.title = 'xxxx';
copy.put(); // payload was: undefined: 12842
});
}
// I also tried customPUT...
// copy.customPUT(copy, '', {}, {'Content-Type':'application/x-www-form-urlencoded'});
I tried "fixing" the id other ways too, too. like this:
Restangular.extendModel('members', function(model) {
model.id = model.personID;
return model;
});
but that messed up the urls, causing missing ids. And I tried getIdFromElem, but it only got called for my objects created with Restangular.one(), not with Restangular.all()
Restangular.configuration.getIdFromElem = function(elem) {
console.log('custom getIdFromElem called');
if (elem.route === 'members') { // this was never true
return elem[personID];
}
};
It seems like Restangular needs to substitute 'personID' most of the time, but maybe it needs 'Person_ID' at some point during the Save? Any ideas on what I could try to get the Save working?
I finally figured it out! The problem was in my config code and in the way I was decamelizing. Because of inconsistencies in my db field names (most use underscores, but some are already camelCase), I was storing the server's original elem names in an array within the jsonResultsAdapterProvider. But since I was calling jsonResultsAdapterProvider.$get().camelizeKeys(extractedData); within the interceptors, I was reinstantiating the array each time I made a new request. So, the undefined in the PUT request was coming from my decamelizeKeys() method.
My updated config code fixed the problem:
RestangularProvider.setBaseUrl(remoteServiceName);
RestangularProvider.setRestangularFields({id: 'personID'});
var jsonAdapter = jsonResultsAdapterProvider.$get();
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
if (data.error) {
return data.error;
}
var extractedData = data.result;
// return extractedData;
return jsonAdapter.camelizeKeys(extractedData);
});
RestangularProvider.addRequestInterceptor(function(elem, operation, what, url) {
return jsonAdapter.decamelizeKeys(elem);
});