Output values from nested Api/Laravel Collection response in vuejs - laravel

I'm trying to output values from an axios promise to my vue component. So far I'm still getting an error [Vue warn]: Error in render: "TypeError: Cannot read property 'surname' of null". Below is what my code looks like
<template>
<div>
{{user.surname}}
</div>
</template>
<!-- ----------------------------------------------------------------------------------- -->
<script>
export default {
name: 'EmployeeCard',
data(){
return{
user: null
}
},
methods:{
getUser(){
axios.get('/api/users/'+ this.$route.params.id)
.then ( response => {
this.user = response.data.data;
})
}
},
mounted(){
this.getUser();
}
}
</script>
This is the actual data returned from the api
{
"data": [
{
"data": {
"id": 11,
"surname": "Hand",
"first_name": "Westley",
"other_name": "Collier",
"email": "ole48#example.com",
"phone_number": "306-755-6192 x493",
"birthday": "06/21/1991",
"company_id": 3,
"department_id": 6,
"job_id": 1,
"state_id": 11,
"marital_status": "married",
"gender_id": 2,
"photo": null,
"is_admin": 0,
"date_of_employment": null,
"job": {
"id": 1,
"title": "HR Manager",
"comment": null,
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
},
"department": {
"id": 6,
"name": "Technical",
"created_at": "2019-10-30 17:38:43",
"updated_at": "2019-10-30 17:38:43"
},
"gender": {
"id": 2,
"name": "Female",
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
},
"company": {
"id": 3,
"name": "Cometshipping",
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
},
"employmentstatus": {
"id": 1,
"name": "Full Time Permanent",
"comment": null,
"created_at": "2019-10-30 17:38:42",
"updated_at": "2019-10-30 17:38:42"
}
}
}
]
}

<template>
<div>
{{surname}}
</div>
</template>
<!-- ----------------------------------------------------------------------------------- -->
<script>
export default {
name: 'EmployeeCard',
data(){
return{
user: null
}
},
computed: {
surname () {
if (this.user) {
return this.user.surname
}
}
}
methods:{
getUser(){
axios.get('/api/users/'+ this.$route.params.id)
.then ( response => {
this.user = response.data[0].data;
})
}
},
mounted(){
this.getUser();
}
}
</script>

Your user variable will initially be null, and you can't get properties from a null value. Therefore, you should replace {{ user.surname }} With {{ user ? user.surname : '' }}.
Another issue is that the data property from your response is an array, not an object, so in your mounted hook you can't do this.user = response.data.data. Instead, you should do this.user = response.data[0].data.
That way, while your user isn't fetched you'll display an empty text instead of getting an error.
Also, I suggest you add a catch hook to your promise to tend to any possible errors.

<template>
<div>
{{ user.surname }}
</div>
</template>
<script>
export default {
name: 'EmployeeCard',
data(){
return{
user: {}
}
},
methods:{
getUser(){
axios.get('/api/users/'+ this.$route.params.id)
.then ( {data} => {
this.user = data[0].data;
})
}
},
mounted(){
this.getUser();
}
}
</script>

Related

Apollo is not letting me edit an object field because it is readonly, but I cannot just make a copy of it

I am not sure how I should set cart.items to a new array, I have already made a copy of the original cache because I learned Apollo does not let you directly edit the cache, but I am still getting the following error
Error: Cannot assign to read only property 'items' of object '#'
Do I need to make a copy of the items array? And if so how do I go about changing the array on the current objects item field?
Here are my console.logs
You can ignore the typename fields as they are irrelevant to the problem
addItem
{
"__typename": "Cart",
"items": [
{
"__typename": "CartItem",
"name": "Item 3"
},
{
"__typename": "CartItem",
"name": "Item 4"
},
{
"__typename": "CartItem",
"name": "New Item!"
}
]
}
carts
{
"carts": [
{
"__typename": "Cart",
"id": "1",
"items": [
{
"__typename": "CartItem",
"id": "1",
"name": "Item 1"
},
{
"__typename": "CartItem",
"id": "2",
"name": "Item 2"
}
]
},
{
"__typename": "Cart",
"id": "2",
"items": [
{
"__typename": "CartItem",
"id": "3",
"name": "Item 3"
},
{
"__typename": "CartItem",
"id": "4",
"name": "Item 4"
}
]
}
]
}
So it seems you need to remake the items array as well since items is its own gql object type the easiest way to do this was to do it all at once with a map.
Please note the comment as that was an important detail I learned
// IMPORTANT NOTE when updating the cache of a query you must return the
// same fields as the original query even if you aren't using them in the code
const GET_CARTS = gql`
query {
carts{
id
items{
id
name
}}} `;
const MUTATION = gql`
mutation AddItem($input:MutationAddItemInput!) {
addItem(input: $input){
items{
id
name
}
}
}
`;
const { loading, error, data } = useQuery(GET_CARTS)
const [addItem] = useMutation(MUTATION, {
// refetchQueries: [{ query: GET_CARTS }]
update(cache, { data: { addItem } }) {
// addItem is the response of the query of add item function
console.log({ addItem });
// #ts-ignore
let { carts } = cache.readQuery({ query: GET_CARTS });
console.log({ carts })
// make a new array out of the carts array and add the new item to the array if the id of the cart is 2
let newCarts = carts.map((cart: Cart) => {
if (cart.id === "2") {
return { ...cart, items: [...addItem.items] }
} else {
return cart
}
})
console.log({ newCarts });
cache.writeQuery({
query: GET_CARTS,
data: { carts: newCarts }
// data: { carts: [{ id: "1", items: [{ id: "2", name: "an item" }] }] }
})
}
})
And lastly you will call the addItem function from the use mutation hook

Laravel 9 Rest API - pagination meta tag unavaible when return it with response()

Controllers/Komic Controller
public function search($value)
{
// Query Wildcards and Resources
$result = new KomikCollection(Komik::where('judul', 'like', '%'. $value .'%')->paginate(2));
return $result;
}
its fine when i directly return the $result
{
"data": [],
"links": {
"first": "http://localhost:8000/api/komik/a?page=1",
"last": "http://localhost:8000/api/komik/a?page=2",
"prev": null,
"next": "http://localhost:8000/api/komik/a?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 2,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://localhost:8000/api/komik/a?page=1",
"label": "1",
"active": true
},
{
"url": "http://localhost:8000/api/komik/a?page=2",
"label": "2",
"active": false
},
{
"url": "http://localhost:8000/api/komik/a?page=2",
"label": "Next »",
"active": false
}
],
"path": "http://localhost:8000/api/komik/a",
"per_page": 2,
"to": 2,
"total": 4
}
}
but when i'll return it using helpers/response
public function search($value)
{
// Query Wildcards and Resources
$result = new KomikCollection(Komik::where('judul', 'like', '%'. $value .'%')->paginate(2));
// send response
return response()->json($result, 200);
}
the meta and link on the json response will be disapppear and return result like this
{
"id": 1,
"title": "Spare me, Great Lord !"
},
{
"id": 2,
"title": "I'm An Evil God"
}
I want the response include the meta and link tags, how do i fix this?
If you want to meta data with response then you must need to add ->response()->getData(true) in collection results.
So your final function looks like :
public function search($value)
{
// Query Wildcards and Resources
$result = new KomikCollection(Komik::where('judul', 'like', '%'. $value .'%')->paginate(2))->response()->getData(true);
// send response
return response()->json($result, 200);
}

How do I render my results using graphql in Vuejs

I am learning graphql and using strapi as a backend nuxt as a front end
I have set up the backend and am now trying to display the results
I have the following code, it is returning the results but I cannot for the life of me figure out how to display just the name field, can you assist
<template>
<div>
<!-- Events are displayed here -->
<div
v-for='organisation in organisations'
:key='organisation.id'
>
test {{ organisation }}
</div>
</div>
</template>
<script>
import gql from "graphql-tag";
export default {
data() {
return {
};
},
apollo: {
organisations: gql`
query organisations {
organisations {
data {
attributes {
name
}
id
}
}
}`
}
};
</script>
returns
test [ { "attributes": { "name": "Organisation 1", "__typename": "Organisation" }, "id": "1", "__typename": "OrganisationEntity" }, { "attributes": { "name": "test2", "__typename": "Organisation" }, "id": "2", "__typename": "OrganisationEntity" } ]
test OrganisationEntityResponseCollection
if i try {{ organisation.name }} it returns no error but nothing displayed, if I try {{ organisation.attributes.name }} i get an error
Thanks
Ah, I should have had
v-for='organisation in organisations.data'
in my v-for, now working

change hasManyThrough() relation attribute name through accessor

I have 3 Models
Campaign PK(id)
CampaignMedium FK(campaign_id)
AccountReceivable FK(campaign_medium_id) (has an amount column)
Controller function:
public function all()
{
return Campaign::with(['customer', 'receivedPayments'])->get();
}
In Campaign Model relationships are defined as follows:
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function accountReceivable()
{
return $this->hasManyThrough(AccountReceivable::class, CampaignMedium::class);
}
public function receivedPayments()
{
return $this->accountReceivable()
->selectRaw('sum(account_receivables.amount) as total')
->groupBy('campaign_id');
}
public function getReceivedPaymentsAttribute()
{
if (!array_key_exists('receivedPayments', $this->relations)) {
$this->load('receivedPayments');
}
$relation = $this->getRelation('receivedPayments')->first();
return ($relation) ? $relation->total : 0;
}
Final Output:
{
"data": [
{
"id": 8,
"name": "example",
"image": "campaign/90375849f6c3cc6b0e542a0e3e6295b890375849f6c3cc6b0e542a0e3e6295b8.jpeg",
"amount": 10,
"description": "saddsa",
"start_at": "2019-02-12 00:00:00",
"end_at": "2019-02-12 00:00:00",
"due_at": "2019-02-12 00:00:00",
"status": "active",
"customer": {
"id": 1,
"name": "test",
"email": "info#test.com",
"image": "customer/ec812116705ff3ae85298234fe6c4e97ec812116705ff3ae85298234fe6c4e97.jpeg",
"address": "sample address"
},
"received_payments": [
{
"total": "700",
"laravel_through_key": 8
}
]
},
{
"id": 9,
"name": "example",
"image": "campaign/fff9fadc92a809513dc28134379851aafff9fadc92a809513dc28134379851aa.jpeg",
"amount": 10,
"description": "saddsa",
"start_at": "2019-02-12 00:00:00",
"end_at": "2019-02-12 00:00:00",
"due_at": "2019-02-12 00:00:00",
"status": "active",
"customer": {
"id": 1,
"name": "test",
"email": "info#test.com",
"image": "customer/ec812116705ff3ae85298234fe6c4e97ec812116705ff3ae85298234fe6c4e97.jpeg",
"address": "sample address"
},
"received_payments": []
}
]
}
summary: trying to get the sum of AccountReceivable amount attribute, which is working fine but the getReceivedPaymentsAttribute() isn't working which needs to return the total value only. also can anyone please help me to explain why laravel_through_key is added with received_payments?
I've never tried to use an attribute modifier to modify a relation this way. You are overriding the expected result of receivedPayments(). You might be better off to define a separate attribute like so:
public function getSumReceivedPaymentsAttribute()
{
// ...your code...
}
Now you can access the attribute using $model->sum_received_payments or always preload it using:
// model.php
protected $appends = ['sum_received_payments'];

Integrating AngularJS into Spring Application

I currently have a method in my controller which does this:
#RequestMapping(value="/angular", produces="application/json")
public #ResponseBody Page handleAngularRequest(Model model, HttpServletRequest httpRequest){
return pageObject;
}
This returns all json data to the page like so:
{
"pageId": null,
"organizationId": null,
"pageModule": "browse",
"pageTitle": null,
"pkId": null,
"templateId": null,
"dataMap": null,
"pageEventList": null,
"pageElementList": null,
"tableId": null,
"elementId": null,
"elementDictionaryList": null,
"elementDictionaryEventList": null,
"elementIds": null,
"pageDataMap": {
"pageObjectId": "",
"module": "REQUISITION",
"mailId": "test#example.com",
"sessionId": "9d538ba3-2d41-4d5b-9f0d-4ac467f5e62e",
"requestId": "21061c6c-2868-46c7-bd31-bbebfb2eee4e",
"userId": "JHUBBARD0000000",
"pages": "",
"systemId": "9d538ba3-2d41-4d5b-9f0d-4ac467f5e62e",
"service": "",
"formatHeader": "Y",
"extrinsic": {
"pageObjectId": "",
"module": "REQUISITION",
"mailId": "test#example.com",
"sessionId": "9d538ba3-2d41-4d5b-9f0d-4ac467f5e62e",
"requestId": "21061c6c-2868-46c7-bd31-bbebfb2eee4e",
"userId": "test",
"pages": "",
"systemId": "9d538ba3-2d41-4d5b-9f0d-4ac467f5e62e",
"service": "",
"formatHeader": "Y"
},
"header": {
"RequisitionHeader_icReqHeader": ""
}
}
}
My question is: How do I get this data into an AngularJS controller/workflow so I can start bindding it and putting it onto a page?
A quick start-up would be like this:
http://plnkr.co/edit/uUj4MV3RvZB2P4uJt35H?p=preview
This will show the page.pageDataMap.mailId property from the JSON response.
app.js
angular.module('app', [])
.service('ApiService', ['$http', '$q', function($http, $q) {
return {
query: function() {
var deferred = $q.defer();
$http.get('/angular')
.success(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
};
}])
.controller('Controller', ['ApiService', '$scope', function(ApiService, $scope) {
$scope.page = {};
$scope.refresh = function() {
ApiService.query()
.then(function(data) {
$scope.page = data;
});
};
$scope.refresh();
}])
index.html
<div ng-app="app" ng-controller="Controller">
<div ng-bind="page.pageDataMap.mailId"></div>
</div>

Resources