AspNetCore EntityModel can't serialize to Json - json

I'm working on a project in AspNetCore with EntityFrameworkCore and i would like to use Ajax to get an object but my controller can't serialize this object correctly in Json, so my Ajax call trigger an error instead of a success event.
Here is my controller + test JsonConvert that return null.
[HttpGet]
public async Task<IActionResult> GetPackWithAllCards(int? packId)
{
if (packId == null)
{
return Json("An error has occured");
}
else
{
var pack = await _context.Packs
.Include(p => p.TagPacks)
.ThenInclude(tp => tp.Tag)
.Include(p => p.CardPacks)
.ThenInclude(cp => cp.Card)
.ThenInclude(c => c.FaceCards)
.ThenInclude(fc => fc.Face)
.ThenInclude(fc => fc.Template)
.Include(p => p.CardPacks)
.ThenInclude(cp => cp.Card.FaceCards)
.ThenInclude(fc => fc.Face.Image)
.Include(p => p.CardPacks)
.ThenInclude(cp => cp.Card.FaceCards)
.ThenInclude(fc => fc.Face.Sound)
.SingleOrDefaultAsync(m => m.PackId == packId);
//pack is correctly returned from database
if (pack == null)
{
return Json("An error has occured");
}
var a = JsonConvert.SerializeObject(pack);
return Ok(pack);
}
}
and my ajax call with typescript object:
var pack = new Pack(0, 0, 0, "", "", 0, 0, false, null, null);
$.ajax({
type: "GET",
url: "/pack/GetPackWithAllCards",
dataType: "text",
data: {packId},
async: false,
success: function (response) {
$.extend(pack, response);
alert("succes:"+response.packId);
},
error: function (response) {
$.extend(pack, response);
alert("error:" + response);
}
});
alert(pack);
return pack;
I hope someone could help me, i really don't find a solution to my problem.

I do this:
return new ContentResult
{
Content = JsonConvert.SerializeObject(data, Formatting.None, new JsonSerializerSettings {ReferenceLoopHandling = ReferenceLoopHandling.Ignore}),
ContentType = "application/json"
};
Are you getting the packId value in the controller? you may need to use:
data: {packId : packId},

Related

I am getting error sending status code in laravel apide

When sending response code in laravel api, validation does not enter.
I can view it from the network, but when I send the status code, the console prints an error and I cannot print the validations on the blade page. If I don't send status code I can print validations.
Following my code: StudentController
public function store(Request $request): object
{
$validate = Validator::make($request->all(),[
'name' => 'required',
'course' => 'required',
]);
$data = [
'name' => $request->name,
'course' => $request->course,
];
if ($validate->fails()){
return response()->json(['success' => false, 'errors' => $validate->messages()->all()],422);
}
Student::insert($data);
return response()->json(['success' => true, 'message' => "Registration Successful"]);
}
ajax
$(document).ready(function (){
$('#createBtn').on('click',function (e) {
e.preventDefault();
let form = $('#student-add').serialize();
$.ajax({
'url': "{{ route('students.store') }}",
'data': form,
'type': "POST",
success:function (result) {
$('#ajax-validate ul').text("");
if(result.success === true){
console.log("True");
}else {
result.errors.forEach(function (item) {
$('#ajax-validate ul').append('<li>'+item+'</li>');
});
}
}
});
});
});
console
network
You have your response.errors.forEach inside of your success: function(), but 422 (or any 400) code doesn't get handled by the success function, but rather the error function:
$(document).ready(function () {
$('#createBtn').on('click', function (e) {
e.preventDefault();
let form = $('#student-add').serialize();
$.ajax({
url: "{{ route('students.store') }}",
data: form,
type: 'POST',
success: function (result) {
if (result.success === true) {
// Do whatever on `2XX` HTTP Codes
}
},
error: function (response) {
if (response.status === 422) {
let responseJson = response.responseJSON ? response.responseJSON : { errors: [] };
$('#ajax-validate ul').text('');
responseJson.errors.forEach(function (item) {
$('#ajax-validate ul').append('<li>'+item+'</li>');
});
} else {
console.log('Unhandled Error:', response)
}
}
});
});
});
Now when an 422 error is explicitly triggered, you code can properly handle the validation errors.

LOG {"_U": 0, "_V": 0, "_W": null, "_X": null} inside fetch API

I am getting this error when I console data returned from function that fetch data from back end
{"_U": 0, "_V": 0, "_W": null, "_X": null}
here is below the code:
const events_data = [];
function getvals() {
return fetch('http://PCIP:3000/users/timetable')
.then((response) => response.json())
.then((output) => {
return addData(output, events_data);
})
.catch(error => console.log(error))
}
function addData(data, data2) {
data.map((d) => {
data2.push({
title: d.name,
startTime: genTimeBlock(d.day, d.start_time),
endTime: genTimeBlock(d.day, d.end_time),
location: d.location,
extra_descriptions: [d.extra_descriptions],
});
});
}
const data = getvals();
console.log(data); // the error come from here
I have checked answers here but nothing worked for me
fetch API always returns {“_U”: 0, “_V”: 0, “_W”: null, “_X”: null}
How do I access promise callback value outside of the function?
This is because the fetch promise has not return a response yet,
There two way to solve the issue , first you create another async funciton and use it to await for the response
const events_data = [];
async function getvals() {
return fetch('http://PCIP:3000/users/timetable')
.then((response) => response.json())
.then((output) => {
return addData(output, events_data);
})
.catch(error => console.log(error))
}
function addData(data, data2) {
data.map((d) => {
data2.push({
title: d.name,
startTime: genTimeBlock(d.day, d.start_time),
endTime: genTimeBlock(d.day, d.end_time),
location: d.location,
extra_descriptions: [d.extra_descriptions],
});
});
}
async function waitForResponse() {
let resp = await getvals();
return resp;
}
const data = waitForResponse();
console.log(data); // the error come from here
The other way would be using state hooks, passing the return obj to state hook on response.
Function for API call:
export const getApplication = async (URL, headers) => {
let data;
await fetch.get(URL, headers).then(res => data = res.data).catch(err => err);
return data;
}
You can call the API from anywhere after importing it:
getApplication(`your url`, {
headers: {
Authorization: AUTH_TOKEN,
},
}).then(res => console.log(res)).catch(err => console.log(err));

No data of first load

I'm new to NgRx, and trying to retrieve and cache paginated table data using Effects and http request.
But on any first time page load (if page isn't cached already) I got empty page, even though if I do console.log of state object, I see data inside?
When I go on previous page, data is there, so I'm guessing something in async world I'm doing wrong, but can't figure out what :/
here is my initialization in
component.ts
ngAfterViewInit() {
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
merge(this.sort.sortChange, this.paginator.page)
.pipe(
startWith({}),
switchMap(() => {
this.isLoadingResults = true;
this.store.dispatch(new ListLoad(this.getQueryParams()));
return this.store.pipe(select('list'));
}),
map((state: State) => {
this.isLoadingResults = false;
this.resultsLength = state.totalRecords;
return this.cacheKey in state.data ? state.data[this.cacheKey] : [];
}),
catchError((err) => {
this.isLoadingResults = false;
this.resultsLength = 0;
return observableOf([]);
})
)
.subscribe((data: any[]) => {
return this.data = data
});
}
and here is my effect definition
effects.ts
#Effect()
loadData = this.actions$.pipe(
ofType(actions.actionTypes.ListLoad),
mergeMap((action: actions.actionTypes.ListLoadSuccess) => this.service.getAll(action.payload).pipe(
map(
response => {
let apiResponse = new ApiResponse(response);
let cacheKey = JSON.stringify(action.payload);
return apiResponse.isSuccess ?
new actions.ListLoadSuccess({ key: cacheKey, data: apiResponse.data }) :
new actions.ListLoadFailed(`code: ${apiResponse.status.error_code}; message: ${apiResponse.status.error_message}`);
}
),
catchError(err => observableOf(new actions.ListLoadFailed(err)))
))
)
In addition to this, I would like to cancel http request, if page containing the data is present in NgRx store
I was able to resolve it. Issue was that I was updating property of store which is object, by adding new property to it. Store does not emit event that fragment is updated, so Select subscription is not triggered. I've introduced another boolean param for loading state, which I listen for changes, and if loading is false (page is loaded), I select desired fragment.
I've also added extra code for page caching
component.ts
ngOnInit() {
this.isLoadingResults$ = this.store.pipe(
select(state => state.stateFragment.isListLoading),
takeWhile(() => this.componentActive) //unsubscribe
);
this.store.dispatch(new ListLoad());
this.isLoadingResults$.pipe(
filter((isLoading:boolean) => !isLoading),
switchMap(() => this.store.pipe(
select(state => state.stateFragment),
takeWhile(() => this.componentActive) //unsubscribe
)),
map(...)
).subscribe(...);
//Other stuff here
}
effects.ts
#Effect()
load$ = this.actions$.pipe(
ofType(actions.actionTypes.ListLoad),
withLatestFrom(this.store.pipe(select(state.stateFragment))),
filter(([action, store]) => {
let isPageCached: boolean = action.payload in store.stateFragment;
if (isPageCached) {
this.store.dispatch(new actions.ListLoaded()); //for sake of changing loading state
}
return !isPageCached;
}),
switchMap(([action, store]) => {
return this.service.getAll(action.payload).pipe(
map(
response => {
let apiResponse = new ApiResponse(response);
return apiResponse.isSuccess ?
new actions.ListLoadSuccess({ key: action.payload, data: apiResponse.getData(), totalRecords: apiResponse.getTotalCount() }) :
new actions.ListLoadFailed(`code: ${apiResponse.status.error_code}; message: ${apiResponse.status.error_message}`);
}
),
catchError(err => observableOf(new actions.ListLoadFailed(err)))
);
}
), share()
)
reducer.ts
export function reducer(state = initialState, action: Actions) {
switch (action.type) {
case actionTypes.ListLoad:
return {
...state,
isListLoading: true
};
case actionTypes.ListLoaded:
return {
...state,
isListLoading: false
};
case actionTypes.ListLoadSuccess:
state.listData[action.payload.key] = action.payload.data;
return {
...state,
isListLoading: false,
listData: state.listData,
listTotal: action.payload.totalRecords
};
case actionTypes.ListLoadFailed:
return {
...state,
isListLoading: false,
error: action.payload
};
case actionTypes.ListClear:
return {
...state,
listData: {},
listTotal: 0
};;
default:
return state;
}
}

Ajax call always returns in error from controller Magento 2

From my controller, I return a JSON data to my Ajax call but it always goes in the error section, even when it's not an error.
jQuery.ajax({
type: 'POST',
url: '/yxcustomer/index/emailpreferences',
data: {"category1": category1,"category2":category2 , "category3":category3,"category4":category4,"category5":category5,"category6":category6,"category7":category7,
"latest1":latest1,"latest2":latest2,"latest3":latest3,"latest4":latest4,
"frequency":frequency,
"email":email,"firstName":firstName , "lastName":lastName},
dataType: "json",
success: function (data) {
console.log("data response success prefe " + JSON.stringify(data));
},
error: function (error) {
console.log("data response error prefe " + JSON.stringify(error));
}
});
Controller code
protected $resultJsonFactory;
public function __construct(
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
\Magento\Framework\App\Action\Context $context
) {
$this->resultJsonFactory = $resultJsonFactory;
parent::__construct($context);
}
public function execute()
{
try{
return $this->resultJsonFactory->create()->setData(['success' => true,'contact'=>json_encode($contact) ,'message' => $this->messageManager->addSuccessMessage("Successfully updated email preferences")]);
} catch (Exception $e) {
return $this->resultJsonFactory->create()->setData(['success' => false,'message' => $this->messageManager->addErrorMessage('Email preferences cannot be updated')]);
}
}
Still that success code
$this->resultJsonFactory->create()->setData(['success' => true,'contact'=>json_encode($contact) ,'message' => $this->messageManager->addSuccessMessage("Successfully updated email preferences")])
Always goes in ajax error part
error: function (error) {}
the response in Ajax is
data response error prefe {"readyState":4,"responseText":"reading contacts with equalto filter\n{\"success\":true,\"contact\":\"{"id":"c74668c8-e886-4592-8950-273a7a6ab72d","email":"an#gmail.com","status":"onboarding","msgPref":"html","source":"api","customSource":"source","created":"2019-03-20T13:10:40-04:00","modified":"2019-03-21T03:44:36-04:00","deleted":false,"fields":[{"fieldId":"0bc403e9000000000000000000000005c10d","content":""},{"fieldId":"0bc403e9000000000000000000000005c10f","content":"Fluid"},{"fieldId":"0bc403e9000000000000000000000005c10e","content":"Men"},{"fieldId":"91c22871-0947-4f63-b067-4290ce18c0a0","content":"Anupam"},{"fieldId":"0bc403e9000000000000000000000005c111","content":""},{"fieldId":"0bc403e9000000000000000000000005c110","content":""},{"fieldId":"0bc403e9000000000000000000000005c113","content":"All"},{"fieldId":"0bc403e9000000000000000000000005c112","content":""},{"fieldId":"0bc403e9000000000000000000000005c115","content":""},{"fieldId":"0bc403e9000000000000000000000005c114","content":"New Arrivals"},{"fieldId":"0bc403e9000000000000000000000005c117","content":"Never Mind"},{"fieldId":"0bc403e9000000000000000000000005c116","content":""},{"fieldId":"0bc403e9000000000000000000000005c0e8","content":""},{"fieldId":"2b0a63f9-cb2d-4fc7-bcc5-06b30b59f8db","content":"singh"}],"numSends":0,"numBounces":0,"numOpens":0,"numClicks":0,"numConversions":0,"conversionAmount":0}\",\"message\":{}}","status":200,"statusText":"OK"}
What am I doing wrong, is there some Magento 2 issue?
In Magento 2, the $resultJsonFactory is used to return the data in JSON format, and you are already doing that which is correct. But, the response goes into the error function of your AJAX request because from the controller, you are encoding the $contact data again in JSON. So, just remove the json_encode like below:
return $this->resultJsonFactory->create()->setData([
'success' => true,
'contact' => $contact,
'message' => $this->messageManager->addSuccessMessage("Successfully updated email preferences")
]);
instead of:
return $this->resultJsonFactory->create()->setData([
'success' => true,
'contact' => json_encode($contact),
'message' => $this->messageManager->addSuccessMessage("Successfully updated email preferences")
]);

Convert Promise object to JSON in Angular 2

I'm trying to make an HTTP POST and then check the response to see if it fails or succeeds.
The HTTP call looks like this :
doLogin(credentials) {
var header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username=' + credentials.username + '&password=' + credentials.password;
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(
data => {
resolve(data.json());
},
error => {
resolve(error.json());
}
);
});
}
And the call of this function is the following :
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
result => {
this.data = result;
console.log(this.data);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
On Chrome console, the data is the following :
Object {status: "Login success", token: "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJjcmlzdGkiLCJ1c2VyS…blf1AzZ6KzRWQFNGXCrIeUHRG3Wrk7ZfCou135WmbVa15iYTA"}
How can I access the status in Angular 2? Because if I'm trying to access this.data.status, it's not working.
Should I create a class with the status and token properties?
To answer your question, you can use the response.okboolean that's available in the subscription of the observable from the http.
So based on your code you could pass the data object straight to the promise and inspect data.ok before parsing the data.json.
//...
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(resolve,
error => {
reject(error.json());
}
);
});
// then you would have something like this:
this._loginService.doLogin(this.credentials).then(
result => {
if (result.ok) {
this.data = result;
console.log(this.data);
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
})
SUGGESTION
Now, I would recommend getting rid of the promise, as I believe you don't really need it. whoever is consuming your service can just subscribe to the observable returned by the http post, like so:
doLogin(credentials) {
let header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username='+credentials.username+'&password='+credentials.password;
return this.http.post(this.url, body, { headers: header });
}
Then, when logging in:
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).subscribe(response => {
if (response.ok) { // <== CHECK Response status
this.data = response.json();
console.log(this.data);
} else {
// handle bad request
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Hope this helps!
You could do it like this:
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
(result: any) => {
this.data = result;
console.log(this.data);
console.log(this.data.status);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Set the result to type any. That way you'll be able to access the status, however you could create a class and use rxjs/map within your service to populate the class if you so desire.