I trying, searching since several hours and no success
I've a mvc/vue/quasar application where I try to upload a photo from a button
In my cshtml file
<q-input type="file" ref="myFileAvatar" v-on:change="handleFileUpload()" v-model="avatar" style="display:none" accept="image/*"/>
<q-btn round color="primary" icon="cloud_upload" #click="getAvatar" ></q-btn >
I send file from my js, method section
getAvatar: function () {this.$refs.myFileAvatar.$el.click()},
handleFileUpload() {
//const files = Array.from(this.avatar).filter((file) => { return file.size < 102500 && file.type.substring(0, 6) == 'image/' });
let formData = new FormData();
formData.append('ownerID', this.profildata.ownerid);
formData.append('file', this.avatar);
axios.post('/forms/default/uploadProfilImage', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(function (response) {
//TODO
});
}
And in my controler
public JsonNetResult uploadProfilImage(Guid ownerID, HttpPostedFileBase file)
{
resultModel resultUpload = new resultModel();
if (this.Request.Files != null && this.Request.Files.Count == 1)//My old version with q-uploader
{
}
else { resultUpload.status = resultMessage.resultValue.error; resultUpload.message = "Oups, ou sont les fichiers"; }
return JsonNetResult.JsonNet(resultUpload);
}
Problem : file is null even if in developper mode in chrome, I see file is a FileList
ownerID is good... I try several type instead of HttpPostedFileBase but nothing (execpt object give a array of string...)
thanks for your help
finally...
It's a type of parameter problem like I thougth
handleFileUpload() {
if (this.avatar[0].size < 102500 && this.avatar[0].type.substring(0, 6) == 'image/') {
let formData = new FormData();
formData.append('file', this.avatar[0]);//One file
formData.append('ownerID', this.profildata.ownerid);
let self = this
axios.post('/forms/default/uploadProfilImage', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(function (response) {
if (response.data.status == 0) { self.profildata.idFichierAvatar = response.data.model.id; } else { self.showNotifError(response.data.message); }
this.avatar = '';
});
}
else { this.showNotifError("L'image ne répond pas aux critères");}
}
and mvc side
[HttpPost]
public JsonNetResult uploadProfilImage(HttpPostedFileBase file,Guid ownerID )
{
resultModel resultUpload = new resultModel();
if (file != null)
{
}
else { resultUpload.status = resultMessage.resultValue.error; resultUpload.message = "Oups, ou sont les fichiers"; }
return JsonNetResult.JsonNet(resultUpload);
}
##UPDATE : Multiple##
And for multiple files
in q-input add multiple property
in server side :
[HttpPost]
public JsonNetResult uploadProfilImage(HttpPostedFileBase[] files,Guid ownerID )
And To send files from js
handleFile() {
let formData = new FormData();
for (var i = 0; i < this.newfiles.length; i++) {
let fichier = this.newfiles[i];
formData.append('files[' + i + ']', fichier);
}
formData.append('ownerID', this.ownerid);
let self = this
axios.post('/files/joinFile/uploadFiles', formData, { headers: { 'Content-Type': 'multipart/form-data' } })
.then(function (response) {
if (response.data.status == 0) { self.files = response.data.model; } else { self.showNotifError(response.data.message); }
this.newfiles = '';
});
}
I hope it's full for everyone who have same problem :-)
I have the following code
#Injectable()
export class ReceptionService {
private generalInfoDataSrc$ = new BehaviorSubject<any>(null);
public generalInfoData = this.generalInfoDataSrc$.asObservable();
setGeneralInfo(dataSrc: GeneralInfoMModal) {
this.generalInfoDataSrc$.next(dataSrc);
}
}
From my component1 I will set the above as
OnSelect(patient: any) {
let generalInfo = new GeneralInfoMModal();
generalInfo.id = patient.id;
// some other code here
// this.recepService.setGeneralInfo(generalInfo);
}
// from component2
//
ngOnInit() { getPatientDetails() }
getPatientDetails() {
this.receptionService.generalInfoData.pipe(mergeMap(response => {
if (response && response.id) {
this.loading = true;
return this.receptionService.get('User/Get' + response.id, this.sourceobj);
} else {
return of(null);
}
}), takeUntil(this.unsubscribe$)).subscribe(response => {
this.patient = response;
this.loading = false;
}, error => {
this.loading = false;
// this.utility.showMsg('An error occurred while getting user.')
}, () => {
})
}
Every things works well. I keep on selecting a user thereby calling the User/Get api. But if in case if the api returns an error then error part is executed after which when there is a change in behaviorsubject(user is selected) it doesn't call the User/Get. Is there other way of handling errors with behaviorsubject or any other approach to handle the idea. How a behaviorsubject should be used in such a case.
If you are using the same behavior subject over and over again, and if there is an error, you need to set the behavior subject back to null, so that when the next user is set, it will get the latest value.
Try something like this:
getPatientDetails() {
this.receptionService.generalInfoData.pipe(mergeMap(response => {
if (response && response.id) {
this.loading = true;
return this.receptionService.get('User/Get' + response.id, this.sourceobj);
} else {
return of(null);
}
}), takeUntil(this.unsubscribe$)).subscribe(response => {
this.patient = response;
this.loading = false;
}, error => {
this.loading = false;
///////////////////////////////// ADD THIS LINE ///////////////////////
this.recepService.setGeneralInfo(null);
// this.utility.showMsg('An error occurred while getting user.')
}, () => {
})
I want to make my form submission happen server-side in order to not expose my API key. I plan to do this with netlify functions however I don't know how that would look with Axios. I've looked for examples on how to do this but I don't seem to find any. Could some help me I'm stuck as to what to put inside my the Netlify function? If anyone has worked with these two programs and could provide a hand that would be helpful here is my javascript with my submission function.
var form = document.querySelector("#user_form");
let reqHeaders = {
headers: {
Authorization: "Bearer",
}
}
let url = ""
let reqData = {
records: [
{
fields: null
}
]
}
let formData = {
firstName: "",
lastName: "",
email: ""
}
function logData(id, dataObj, value) {
dataObj[id] = value;
console.log(value)
}
function formMessg (id) {
document.querySelector(id).style.display = "block";
setTimeout(function(){
document.querySelector(id).style.display = "none";
form.reset();
}, 2500)
}
form.addEventListener("submit", function (e) {
e.preventDefault();
let spam = document.getElementById('spam').value;
try {
for(const data in formData){
if(formData[data] === "" || spam.length !== 0){
const error = new Error();
error.notVaild = true;
throw error;
}
}
reqData.records[0].fields = formData;
console.log(reqData);
axios.post(url, reqData, reqHeaders).then((res) => {
formMessg ('.success-messg');
form.style.display = "none";
})
.catch ((err) => {
throw err;
});
} catch (err){
if (err.reponse){
formMessg ('.fail-messg');
} else if (err.request) {
formMessg ('.fail-messg');
} else if ("Notvalid") {
formMessg ('.fill-messg');
}else {
console.log(err);
}
}
});
Here's my Angular controller
//Save And Update
$scope.AddUpdateBusinessType = function() {
var businessType = {
Code: $scope.businessCode,
BusiType: $scope.businessType
};
var getBusinessTypeAction = $scope.BusinessTypeAction;
if (getBusinessTypeAction == "Update") {
businessType.BusinessTypeId = $scope.businessTypeId;
var getBusinessTypeData = businessTypeService.updateBusinessType(businessType);
getBusinessTypeData.then(function (msg) {
GetAllBusinessType();
$scope.ClearBusinessTypeForm();
alert("Record Updated Successful");
$scope.BusinessTypeAction = "";
$scope.divBusinessType = false;
}, function () {
alert('Error in Updating Record');
});
} else {
**// Save Section**
var getExistBusinessCode = businessTypeService.checkBusinessTypeCode(businessType.Code);
getExistBusinessCode.then(function (businessTypeCode) {
debugger;
if (businessTypeCode == true) {
alert('Business Type Code Already Exist');
} else {
debugger;
var getBusinessTypeData = businessTypeService.addBusinessType(businessType);
getBusinessTypeData.then(function (msg) {
GetAllBusinessType();
$scope.ClearBusinessTypeForm();
alert("Record Added Successful");
$scope.divBusinessType = false;
}, function () {
alert("Error Occured In Saving Data");
});
}
},function() {
alert('Error Occured While Checking Records');
});
}
}
In the above code Save Section I am trying to check if a value is exists in a database so I'm passing a string value to: checkBusinessTypeCode(businessType.Code) Service.When I Debug and See Value its Seems Normal.
Here's My Service:
//Check Business Code
this.checkBusinessTypeCode = function (businessTypeCode) {
debugger;
var response = $http({
method: "post",
url: "/BusinessType/CheckBusinessTypeDetailByCode",
params: {
businessTypeCode: JSON.stringify(businessTypeCode)
}
});
return response;
}
But when Passing To Controller string value I get some unexpected behavior.
two \\ always appear automatically
example
"\"stringvalue\""
I'm Still Having Above Problem
but as a quick solution i did code as follows
public bool _CheckBusinessTypeDetailByCode(string businessTypeCode)
{
string bisCode = businessTypeCode.Replace("\"", "");
bool isExist;
isExist = _IBusinessTypeRepository.IsExist(x => x.IsActive && !x.IsDelete && x.Code == bisCode);
return isExist;
}
I don't know is it bad practice or not , any way it is solved my problem.
Before did this modification
string businessTypeCode always gives value as
"\"somevalue\""
How can I display ModelState errors returned by JSON?
I want to do something like this:
if (!ValidateLogOn(Name, currentPassword))
{
ModelState.AddModelError("_FORM", "Username or password is incorrect.");
//Return a json object to the javascript
return Json(new { ModelState });
}
What must be my code in the view to read the ModelState errors and display them?
My actual code in the view to read the JSON values is as follows:
function createCategoryComplete(e) {
var obj = e.get_object();
alert(obj.Values);
}
This is draft code but the same idea works for me in production.
The main idea here is that Json errors have predefined tag names, that no normal objects will have. For errors validation errors HTML is re-created using JavaScript (both top summary and form elements highlighting).
Server side:
public static JsonResult JsonValidation(this ModelStateDictionary state)
{
return new JsonResult
{
Data = new
{
Tag = "ValidationError",
State = from e in state
where e.Value.Errors.Count > 0
select new
{
Name = e.Key,
Errors = e.Value.Errors.Select(x => x.ErrorMessage)
.Concat(e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message))
}
}
};
}
in action:
if (!ModelState.IsValid && Request.IsAjaxRequest())
return ModelState.JsonValidation();
Client side:
function getValidationSummary() {
var el = $(".validation-summary-errors");
if (el.length == 0) {
$(".title-separator").after("<div><ul class='validation-summary-errors ui-state-error'></ul></div>");
el = $(".validation-summary-errors");
}
return el;
}
function getResponseValidationObject(response) {
if (response && response.Tag && response.Tag == "ValidationError")
return response;
return null;
}
function CheckValidationErrorResponse(response, form, summaryElement) {
var data = getResponseValidationObject(response);
if (!data) return;
var list = summaryElement || getValidationSummary();
list.html('');
$.each(data.State, function(i, item) {
list.append("<li>" + item.Errors.join("</li><li>") + "</li>");
if (form && item.Name.length > 0)
$(form).find("*[name='" + item.Name + "']").addClass("ui-state-error");
});
}
$.ajax(... function(response) {
CheckValidationErrorResponse(xhr.responseText); } );
Why not return the original ModelState object to the client, and then use jQuery to read the values. To me it looks much simpler, and uses the common data structure (.net's ModelState)
C#:
return Json(ModelState);
js:
var message = "";
if (e.response.length > 0) {
$.each(e.response, function(i, fieldItem) {
$.each(fieldItem.Value.Errors, function(j, errItem) {
message += errItem.ErrorMessage;
});
message += "\n";
});
alert(message);
}
this is a tiny tweak to queen3's client side code which handles specific validation messages, and creates a similar document to that created by MVC3:
function getValidationSummary() {
var $el = $(".validation-summary-errors > ul");
if ($el.length == 0) {
$el = $("<div class='validation-summary-errors'><ul></ul></div>")
.hide()
.insertBefore('fieldset:first')
.find('ul');
}
return $el;
}
function getResponseValidationObject(response) {
if (response && response.Tag && response.Tag == "ValidationError")
return response;
return null;
}
function isValidationErrorResponse(response, form, summaryElement) {
var $list,
data = getResponseValidationObject(response);
if (!data) return false;
$list = summaryElement || getValidationSummary();
$list.html('');
$.each(data.State, function (i, item) {
var $val, lblTxt, errorList ="";
if (item.Name) {
$val = $(".field-validation-valid,.field-validation-error")
.first("[data-valmsg-for=" + item.Name + "]")
.removeClass("field-validation-valid")
.addClass("field-validation-error");
$("input[name=" + item.Name + "]").addClass("input-validation-error")
lblTxt = $("label[for=" + item.Name + "]").text();
if (lblTxt) { lblTxt += ": "; }
}
if ($val.length) {
$val.text(item.Errors.shift());
if (!item.Errors.length) { return; }
}
$.each(item.Errors, function (c,val) {
errorList += "<li>" + lblTxt + val + "</li>";
});
$list.append(errorList);
});
if ($list.find("li:first").length) {$list.closest("div").show(); }
return true;
}
See below for code with a few amendments to Brent's answer. CheckValidationErrorResponse looks for the Validation Summary regardless of whether it's in the valid or invalid state, and inserts it if not found. If validation errors are found in the response, it applies the validation-summary-errors class to the Summary, else it applies validation-summary-valid. It assumes CSS is present to control the visibility of the Summary.
The code clears existing instances of field-validation-error, and reapplies them for errors found in the response.
function getValidationSummary(form) {
var $summ = $(form).find('*[data-valmsg-summary="true"]');
if ($summ.length == 0)
{
$summ = $('<div class="validation-summary-valid" data-valmsg-summary="true"><ul></ul></div>');
$summ.appendTo(form);
}
return $summ;
}
function getValidationList(summary) {
var $list = $(summary).children('ul');
if ($list.length == 0) {
$list = $('<ul></ul>');
$list.appendTo(summary);
}
return $list;
}
function getResponseValidationErrors(data) {
if (data && data.ModelErrors && data.ModelErrors.length > 0)
return data.ModelErrors;
return null;
}
function CheckValidationErrorResponse(data, form, summaryElement) {
var errors = getResponseValidationErrors(data);
var $summ = summaryElement || getValidationSummary(form);
var $list = getValidationList($summ);
$list.html('');
$(form).find(".field-validation-error")
.removeClass("field-validation-error")
.addClass("field-validation-valid");
if (!errors)
{
$summ.removeClass('validation-summary-errors').addClass('validation-summary-valid');
return false;
}
$.each(errors, function (i, item) {
var $val, $input, errorList = "";
if (item.Name) {
$val = $(form).find(".field-validation-valid, .field-validation-error")
.filter("[data-valmsg-for=" + item.Name + "]")
.removeClass("field-validation-valid")
.addClass("field-validation-error");
$input = $(form).find("*[name='" + item.Name + "']");
if (!$input.is(":hidden") && !$val.length)
{
$input.parent().append("<span class='field-validation-error' data-valmsg-for='" + item.Name + "' data-valmsg-replace='false'>*</span>");
}
$input.addClass("input-validation-error");
}
$.each(item.Errors, function (c, err) {
errorList += "<li>" + err + "</li>";
});
$list.append(errorList);
});
$summ.removeClass('validation-summary-valid').addClass('validation-summary-errors');
return true;
}
C#
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
JavaScript
$.ajax({
type: "GET",
url: "/api/xxxxx",
async: 'false',
error: function (xhr, status, err) {
if (xhr.status == 400) {
DisplayModelStateErrors(xhr.responseJSON.ModelState);
}
},
....
function DisplayModelStateErrors(modelState) {
var message = "";
var propStrings = Object.keys(modelState);
$.each(propStrings, function (i, propString) {
var propErrors = modelState[propString];
$.each(propErrors, function (j, propError) {
message += propError;
});
message += "\n";
});
alert(message);
};
If you are returning JSON, you cannot use ModelState. Everything that the view needs should be contained inside the JSON string. So instead of adding the error to the ModelState you could add it to the model you are serializing:
public ActionResult Index()
{
return Json(new
{
errorControl = "_FORM",
errorMessage = "Username or password is incorrect.",
someOtherProperty = "some other value"
});
}