I'm trying to use a custom FormRequest with validation rules for JSON formatted data. If I use same code in controller instead of the FormRequest class then it works fine, see below:
array data (from ajax request):
[
{
"name": "id",
"value": "1"
},
{
"name": "title",
"value": "My fun project"
}
]
Controller:
public function update(Request $request, $id) {
//convert it to readable json
$jsonReq = $request->json()->all();
$jsonData = array();
foreach ($jsonReq as $json) {
$jsonData[$json["name"]] = $json["value"];
}
$rules = [
'id' => 'required|numeric:1',
'title' => 'required|max:255',
];
$validation = Validator::make($jsonData, $rules);
if ($validation->fails()) {
return $validation->errors();
}
}
Above works fine when used in the controller. However, I want to separate my validation in a separate class, extending the FormRequest. This generates some errors, most likely due to the array format.
class UpdateProjectValidationRequest extends FormRequest {
public function rules() {
$jsonReq = $this->json()->all();
$jsonData = array();
foreach ($jsonReq as $json) {
$jsonData[$json["name"]] = $json["value"];
}
return [
'id' => 'required|max:1', //does not work
$jsonData['title'] => 'required|max:255', //does not work
];
}
Controller:
public function update(UpdateProjectValidationRequest $request, $id) {
// validate against rules
$request->rules();
The error message:
{
"message": "The given data was invalid.",
"errors": {
"My fun project": [
"My fun project field is required."
],
"id": [
"The id field is required."
],
Clearly this has to do with the format. Any ideas how to solve this? Note that after the foreach loop the data is formatted to below:
{
"id": "1",
"title": "My Fun project",
}
Ok so i could not solve it using the laravel FormRequest, instead I modified the ajax call itself by serializing it to json instead of an array.
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
//old: var formdata = JSON.stringify(jQuery('#myForm').serializeArray());
var formdata = JSON.stringify(jQuery('#myForm').serializeObject());
Related
I made json code using json encode, the results are correct, but I want to add a satatus response to the object. How to ?
this my code
public function get(){
header('Content-Type: application/json');
$db = $this->M_order->db_order();
$response = array();
$data = array();
foreach ($db as $key) {
$data[] = array(
'id' => $key->id_user,
'name' => $key->name,
'destination' =>$key->destination
);
}
$response['data'] = $data;
echo json_encode($response, TRUE);
}
this result my json
{
"data": [
{
"id": "1",
"name": "amar",
"destination": "USA"
}
]
}
here I want to add a status header in object, like the following ...
{
"status": 200,
"error": false,
"data": [
{
"id": "1",
"name": "amar",
"destination": "USA"
},
]
}
how to create ?
As I understand your question,
$response = array();
$data = array();
foreach ($db as $key) {
$data[] = array(
'id' => $key->id_user,
'name' => $key->name,
'destination' =>$key->destination
);
}
$response['status'] = 200;
$response['error'] = false;
$response['data'] = $data;
I'm trying to make autocomplete textbox using this link
https://github.com/devbridge/jQuery-Autocomplete
but I got this error
Uncaught TypeError: Cannot read property 'length' of undefined
this is my action method
public JsonResult GetNews(string prefix)
{
var newsList = NewsDataRoot.AutoCompleteTitle(prefix).Select(n => new
{
value = n.Title,
data = n.Id
}).ToList();
var myjson = Json(newsList, JsonRequestBehavior.AllowGet);
return myjson;
}
and it return this result when I test it in browser
[{"value":"this is a test","data":2006}]
I found the format must be
{
suggestions: [{
"value": "United Arab Emirates",
"data": "AE"
}, {
"value": "United Kingdom",
"data": "UK"
}, {
"value": "United States",
"data": "US"
}, {
"value": "United Funes",
"data": "DAN"
}]
}
how can do this?
thanks a lot!
also as you can see I tried transformResult but it doesnt worked
<script>
$('#autocomplete').autocomplete({
serviceUrl: '/TestAutoComplete/GetNews',
paramName: 'prefix',
transformResult: function(response) {
return {
suggestions: $.map(response.myData, function(dataItem) {
return { value: dataItem.valueField, data: dataItem.dataField };
})
};
},
onSelect: function (suggestion) {
alert('You selected: ' + suggestion.value + ', ' + suggestion.data);
}
});
</script>
Try this, creates an anonymous object which just has the suggestions property
var newsList = NewsDataRoot.AutoCompleteTitle(prefix)
.Select(n => new {
value = n.Title,
data = n.Id
}).ToList();
var myjson = Json(new { suggestions = newsList }, JsonRequestBehavior.AllowGet);
if you want to set number to be numeric string you can try convert its value to string
public JsonResult GetNews(string prefix)
{
var newsList = NewsDataRoot.AutoCompleteTitle(prefix).Select(n => new
{
value = n.Title,
data = n.Id.ToString()
}).ToList();
var myjson = Json(new {suggestions = newsList}, JsonRequestBehavior.AllowGet);
return myjson;
}
i have a simple subscribe to observable in a function:
public MyGet () {
let results={};
this.http.get("myfile.json").map(res => res.json()).subscribe(
output => {
results=output.clients; // clients is the root of json file
},
/* etc */
The json file "myfile.json" is:
{
"clients" : [
{ "name":"X",
"age":"34" },
{ "name": "Y",
"age": "41" },
/* etc */
I want "clients" as a parameter in the function MyGet:
public MyGet (json_root: any){
let results={};
this.http.get("myfile.json").map(res => res.json()).subscribe(
output => {
results=output.HERE; // HERE = json_root
},
/* etc */
So i can call:
MyGet("clients")
I don't understand how to write the json_root in HERE
You can split your function.
public MyGet (): Observable<any>{
return this._http.get("myfile.json").map(res => res.json());
}
....
private json_root: any;
public callAndSubscrive(json_key: string){
this.MyGet().subscribe(output => {this.json_root = output[json_key]; console.log(output)});
}
On one hand, I have a RESTful HAL HATEOAS collection which looks like this :
{
"page": 1,
"limit": 10,
"pages": 18,
"total": 174,
"_links": {
"self": { "href": "/users?page=1&limit=10" },
"first": { "href": "/users?page=1&limit=10" },
"last": { "href": "/users?page=18&limit=10" },
"next": { "href": "/users?page=2&limit=10" }
},
"_embedded": {
"users": [
{
"name": "bob",
"_links": { "self": { "href": "/users/1" } }
},
...
]
}
}
On the other hand, I have an Angular 2 app.
public getUsers(uri: string = this.baseURI): Observable<User> {
return this.http.get(uri)
.map(res => res.json()._embedded.users as User[])
.flatMap(d => d) // Transform the flux of arrays in flux of users
.catch(this.handleError);
} // Get only the 10th first users
What I'm trying to do have an observable of Users which will append data while _links.next != null
Modified service
public getUsers(uri: string = this.baseURI): Observable<User> {
return this.http.get(uri)
.do(res => {
const uri = JSON.parse(res._body)._links.next.href;
this.nextUri = uri ? uri : null;
})
.map(res => res.json()._embedded.users as User[])
.flatMap(d => d) // Transform the flux of arrays in flux of users
.catch(this.handleError);
}
Recursive function
loadAll(uri: string) {
read(uri)
.subscribe(
user => {
this.stockedUsers.push(user);
},
error => console.log(error),
() => {
if (this.nextUri) {
this.loadAll(this.nextUri);
}
}
);
}
Does someone know how to achieve this properly ?
I want to keep thes advantages of the RxJS flux.
UPDATE/ANSWER
Silly me ! I think I answered myself. Maybe this will help others :
public read(uri: string = this.baseURI): Observable<User> {
return Observable.create(observer => this.iteratePages(observer, uri));
}
private iteratePages(observer: Observer<User>, uri): void {
if (uri == null) { return observer.complete(); }
this.http.get(uri).subscribe(res => {
const data = res.json();
for (const user of data._embedded.users) {
observer.next(user as User);
}
const nextUri = (data._links && data._links.next) ? data._links.next.href : null;
this.iteratePages(observer, nextUri);
});
}
I'm returning some json data as response in a Controller, i want to add some information to
In my DriversController extend's Apicontroller in DriversController i'm returning some data on api call, i want to appent the status code information to below response
if ($request->wantsJson()) {
return Response::json([
'data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
]);
}
//to the above response
return Response::json([
$this->respondSuccess(), // i am append this information
'data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
]);
In ApiControllre I'm setting all the status code and messages
class ApiController extends Controller
{
protected $statusCode = 200;
//getter status code
public function getStatusCode()
{
return $this->statusCode;
}
//setter status code
public function setStatusCode($statusCode)
{
$this->statusCode = $statusCode;
return $this;
}
//failure messages
public function respondFailure($message='Account is not active contact admin', $status='failure')
{
return $this->setStatusCode(400)->respondWithMessage($message, $status);
}
//success messages
public function respondSuccess($message='Agent is active', $status='success')
{
return $this->setStatusCode(200)->respondWithMessage($message, $status);
}
//a layer of abstraction to avoide repetation
public function respond($data, $headers = [])
{
return Response::json($data, $this->getStatusCode(), $headers);
}
//get ststus code and message parse it for errors
public function respondWithMessage($message, $status)
{
return $this->respond([
'status_code' => $this->getStatusCode(),
'status' => $status,
'message' => $message
]);
}
}
But the response i'm getting is different as expected
//expected result
{
"status_code": "200",
"status": "success",
"message": "User details with dropdown data",
"data": {
"user_details": {
"id": 2017001,
"name": "User Name",
"email": "user#email.com",
},
"dropdown_data": {
}
}
}
//getting response
{
"0": {
"headers": {},
"original": {
"status_code": 200,
"status": "success",
"message": "Agent is active"
},
"exception": null
},
"data": {
"user_details": {
"id": 2017001,
"name": "User Name",
"email": "user#email.com",
},
"dropdown_data": {
}
}
}
the middleware
<?php
namespace App\Http\Middleware;
use Closure;
use Response;
use App\Http\Controllers\ApiController;
class UserStatus extends ApiController
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($request->user() === null)
{
return $this->respondFailure();
}
if($request->user()->isActive($request->user()))
{
return $next($request);
}
return $this->respondFailure();
}
}
You are only appending the response from the respondSuccess() and not merging the response.
$this->setStatusCode(200)->respondWithMessage($message, $status);
on this response:
return Response::json([
$this->respondSuccess(), // i am append this information
'data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
]);
It gives the response as you got not the response you expected.
To get the expected response you need to do something like this:
public function respondWithMessage($message, $status)
{
return [
'status_code' => $this->getStatusCode(),
'status' => $status,
'message' => $message
];
}
I have used only array and not $this->respond() because you only have this message:
"status_code": "200",
"status": "success",
"message": "User details with dropdown data",
For the type of response, you might need to merge the two arrays into one.
Look on array_merge() to get more understanding.
$responseMessage= $this->respondSuccess();
$data = ['data' => [
'user_details' => $agent_percentage,
'dropdown_data' => [
'employment_types' => $employment_types->all(),
'roles' => $roles->all(),
'vehicle_brands' => $vehicle_brands->all(),
'vehicle_types' => $vehicle_types->all()
]
]
];
$responseArray = array_merge(responseMessage, data);
return Response::json($responseArray);
I have not yet tested the code but this might give you some understanding of how to get the expected array response you want.
If I am wrong anyone could suggest the edit.