Laravel vue array in array issue - arrays

I'm trying to get data from 2 database tables and return all in 1 table body in my component.
code
controller
public function show($id)
{
$history = Payment::where('account_id', $id)->with('account')->orderby('id', 'desc')->get();
$balance = Account::where('id' , $id)->select('balance')->first();
return response()->json([
$history,$balance
]);
}
component
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th class="text-center">#</th>
<th class="text-center">Date</th>
<th class="text-center">Amount</th>
<th class="text-center">Note</th>
</tr>
</thead>
<tbody>
<tr v-for="(history,index) in histories" #key="index">
<td width="50" class="text-center">{{index+1}}</td>
<td class="text-center" width="100">
{{history.created_at}}
</td>
<td class="text-center" width="300">Rp. {{ formatPrice(history.balance) }}</td>
<td class="text-center">{{history.note}}</td>
</tr>
</tbody>
</table>
export default {
data() {
return {
histories : []
}
},
beforeMount(){
let user_id = this.user.id;
axios.get('/api/account/'+user_id).then(response => this.histories = response.data)
},
// rest of it
</script>
In image above
I get my balance from Account table in histories array while I get histories from Payment table in histories array.
What I want is to take out histories array and join it under histories
right where there balance data is.
So later I can have something like:
histories: array[3]
0:...
1:...
2:...
How can I do that?
Update
I've made changes in my controller and now data result become as I wanted (all in one array) but somehow it doesn't return all data.
code
public function show($id)
{
// $history = Payment::where('account_id', $id)->with('account')->orderby('id', 'desc')->get();
// $balance = Account::where('id' , $id)->select('balance')->first();
$history = DB::table('payments')
->where('account_id', $id)
->join('accounts', 'accounts.id', '=', 'payments.account_id')
->get();
return response()->json($history, 200);
}
It supposed to be 3 but it only returns 2.

Solved
I used push method and now it's working as i wanted. Here is last code for those in need.
public function show($id)
{
$his = Payment::where('account_id', $id)->with('account')->orderby('id', 'desc')->get();
$balance = Account::where('id' , $id)->select('balance')->first();
$history = $his->push($balance);
return response()->json($history, 200);
}
Hope it helps.

Related

Call service for each element found from another service and then populate an array with results

Problem:
Trying to populate a html table with two services. First I'm calling a service to retrieve all products. Then for each element I'm calling another service that accepts the fabricplanid as a parameter and returns the object if exists. If exists I push it to an array, but if returns an error 404 I push a string to the same array.
The problem I'm facing is that the values inside the array, don't match the corresponding fabricPlanId of the product.
This is the product.component.ts file that when called execute this service and populates a table using a ngfor.
products:Product[];
//view
fabricplan: Fabricplan[];
plan_desc: Array<String> = [];
//view select
fabricplans: Fabricplan[];
ngOnInit() {
this.productservice.getProducts().subscribe(products => {
this.products = products;
console.log("Produtos", this.products);
this.products.forEach( element => {
console.log(element.fabricPlanId);
this.fabricplanservice.getfabricplan(element.fabricPlanId).subscribe(
(response) => {
this.fabricplan = response;
this.plan_desc.push(this.fabricplan['description']);
},
(error) => {
if(error.status === 404){
this.plan_desc.push('No fabric plan');
}
});
});
});
console.log("Planos de fabrico", this.plan_desc);
}
The product.component.html file
<table class="table table-hover">
<thead class="thead-dark">
<tr>
<th scope="col">Number</th>
<th scope="col">Fabric Plan</th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th scope="col">Price €</th>
<th scope="col">Ative</th>
</tr>
</thead>
<tbody>
<tr scope="row" id="table" *ngFor="let product of products let i = index"(click)="open(content, product.id)">
<td>{{ i+1 }}</td>
<td>{{ plan_desc[i] }}</td>
<td>{{ product?.name }}</td>
<td>{{ product?.description }}</td>
<td>{{ product?.price }}</td>
<td>{{ product?.active }}</td>
</tr>
</tbody>
</table>
Response body
Products
{
active: true,
description: " descrição do prod 1",
fabricPlanId: 1,
id: 1,
name: "Produto 1",
price: 1
}
FabricPlans
{
dateStart: "2019-10-30T00:00:00"
description: "Descrição do plano 1"
id: 1
operationsIds: [1, 2]
}
Based on your comment, the plan_desc are in a random order. The cause for this is
this.products.forEach( element => {
this.fabricplanservice.getfabricplan(element.fabricPlanId).subscribe(
...
you cannot control how long each request will take, so some will return sooner, some later and whenever they return, they are added to the list --> the order is random.
However it is pretty easy to make a request for each item and then get the list order with rxjs forkjoin
// create a request for each product (dont fire it yet)
const plans_desc$ = this.products.map( element =>
this.fabricplanservice.getfabricplan(element.fabricPlanId).pipe(
// map it to the value you want
map((response) => {
this.fabricplan = response;
return this.fabricplan['description'];
}),
// replace 404 responses with the 'No fabric plan'
// if not 404 throw the error again
catchError((error) => {
if(error.status === 404){
return 'No fabric plan';
} else {
throwError(error);
}
}));
});
// now make the actuall requests. Forkjoin will return, when all requests are completed.
// the order will be the be how the requests where added, not when the completed
forkJoin(plans_desc$).subscribe((plans_desc) => this.plan_desc = plans_desc);
(I wrote his code here)
imports:
import {forkJoin, throwError} from 'rxjs';
import {map, catchError} from 'rxjs/operators';

How to Send multiple values from Asp.Net WebApi to Angularjs Controller?

WebApi Controller.. How to send this value to Angularjs controller (bill = q.TotalBill;)? I have send this (return Ok(gridlist);) into JSON form into angularjs controller
public static double bill; // this is static variable on top of a class
[System.Web.Http.Route("api/Products/gridpro/{id}")]
public IHttpActionResult GetGrid(int id)
{
var q = db.products.Find(id);
if (q != null)
{
var check = gridlist.Where(x => x.Id == id).FirstOrDefault();
if (check != null)
{
check.ProductQty += 1;
check.TotalAmount = check.ProductQty * check.ProductRate;
}
else
{
q.ProductQty = 1;
q.TotalAmount = q.ProductQty * q.ProductRate;
gridlist.Add(q);
}
q.TotalBill = gridlist.Sum(x => x.TotalAmount);
foreach (var item in gridlist)
{
item.TotalBill = q.TotalBill;
}
bill = q.TotalBill; //How to send this value to Angularjs controller
return Ok(gridlist);
}
else
{
return NotFound();
}
}
Anagularjs Code: I see all the data into the HTML using this ($scope.gridproducts) but I want to show (bill = q.TotalBill;) this single value into HTML code
$scope.OnProChange = function (Pro) {
var id = Pro.Id;
$http.get("/api/Products/gridpro/" + id).then(function (response) {
console.log(JSON.stringify(response.data))
$scope.gridproducts = response.data;
})
}
HTML code:How I can show total bill value I use {{gridproducts.TotalBill}} this but nothing works.
<tbody>
<tr ng-repeat="item in gridproducts">
<td>
<a class="delete"><i class="fa fa-times-circle-o"></i></a>
</td>
<td class="name">{{item.ProductName}}</td>
<td>{{item.ProductRate}}</td>
<td>
<input class="form-control qty" style="width:50px" onchange="UpdatePurchaseItem('36',this.value)" value="{{item.ProductQty}}">
</td>
<td>{{item.TotalAmount}}</td>
</tr>
<tr></tr>
<tfoot>
<tr>
<th colspan="2"></th>
<th colspan="2"><b>Total</b></th>
<th><b>{{gridproducts.TotalBill}}</b></th>
</tr>
<tr>
<th colspan="2"><b></b></th>
<th colspan="2"><b>Total Items</b></th>
<th><b>25</b></th>
</tr>
</tfoot>
</tbody>
if you want send multiple values to angularjs , you may create complex type for that.
for example,
in c# code
Public Class GridDataModel<T>
{
public T ItemList{get;set;}
public int TotalBill{get;set}
}
then when you return data to js
var gridData=new GridDataModel<products>()
{
ItemList=gridlist,
TotalBill=q.TotalBill
}
return Ok(gridData);
after doing this , you can create another propert for js scope
$http.get("/api/Products/gridpro/" + id).then(function (response) {
console.log(JSON.stringify(response.data))
$scope.gridproducts = response.data.ItemList;
$scope.totalBill = response.data.TotalBill;
})

Dynamic columns with angular datatables

So I try to generate columns in datatables based on response from api request.
$scope.getProductCustomFields = function() {
$scope.custom_fields_loading = true;
$scope.dtCustomFieldsInstance = {};
$scope.dtCustomFieldsOptions = DTOptionsBuilder.newOptions().withOption('order', []);
$scope.dtCustomFieldsOptions.withOption('ajax', {
headers: {'Authorization': 'Basic ' + $rootScope.globals.currentUser.api_token},
dataSrc: 'data',
url: API.returnUrl('/ecommerce/reports/get-product-custom-fields?' + $httpParamSerializer({product: $scope.product})),
type: 'GET'
})
.withOption('processing', true)
.withOption('serverSide', true)
.withPaginationType('full_numbers')
.withOption('createdRow', createdRow);
function createdRow(row, data, dataIndex) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element(row).contents())($scope);
}
$scope.dtCustomFieldsColumns = [];
//Here I make another request to php within this function since I cannot actually use dataSrc: 'data' as array
ProductsReportsService.getProductCustomFields($scope.product).then(function (response) {
$scope.data = response.data.data;
angular.forEach($scope.data, function (value, key) {
$scope.dtCustomFieldsColumns.push(DTColumnBuilder.newColumn('value.value').withTitle(key).notSortable());
});
});
$scope.custom_fields_loading = false;
};
As you can see I make two requests, a ajax one whose data is not accessible and another one before which I have commented, that I use for my forEach.
data looks like this:
array:1 [
"test drop down" => array:2 [
0 => array:4 [
"id" => 1
"label" => "test drop down"
"value" => "test1"
"name" => "test drop down"
]
1 => array:4 [
"id" => 1
"label" => "test drop down"
"value" => "test2"
"name" => "test drop down"
]
]
So to put it simple what I try to accomplish is table that basically looks like this:
<table>
<thead>
<tr>
<th>test drop down</th>
</tr>
</thead>
<tbody>
<tr>
<td>test1</td>
</tr>
<tr>
<td>test2</td>
</tr>
</tbody>
</table>
Right now my table only has the headers right but I have no data in table body.
<table>
<thead>
<tr>
<th>test drop down</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
</tr>
<tr>
<td></td>
</tr>
</tbody>
</table>
Thank you for your time and help!
Not sure is this is what you're looking for, but displaying a table like that from given data set (assuming it's saved in $scope.dtCustomFieldsColumns) would be something like this:
<tbody>
<tr ng-repeat="column in dtCustomFieldsColumns.testdropdown">
<td>{{column.value}}</td>
</tr>
</tbody>
You should change test drop down key in your data set to something like testDropDown. That'll help you access columns directly. Good luck.

Displaying data with ng-repeat from JSON array in angular

Hi I have following data that is returned from service which I do not have any control on how it is returned:
{"day_1":[{"classroom":"Nursery","count":0},{"classroom":"Junior Kindy","count":1}],"day_2":[{"classroom":"Nursery","count":4},{"classroom":"Junior Kindy","count":0}]}
but I need to display it in pivot format that is like below:
classroom | day_1 | day_2
============ ======== ======
Nursery | 0 | 4
Junior Kindy | 1 | 0
This is the code in controller
$scope.rolls=[];
Rolls.getRollMarked().then(
function(data){
console.log(data.data);
$scope.rolls = data.data;
}
)
in the view I am using following but it doesn't display any count for the day and I am not sure how to display it..so please let me know how can I display it in the above format?
<table class="table table-bordered">
<tr>
<td>Classroom</td>
<td>day_1</td>
<td>day_2</td>
</tr>
<tr ng-repeat="roll in rolls">
<td>
{{roll[$index]['classroom']}}
</td>
<td>
{{roll.day_1}}
</td>
<td>
{{roll.day_2}}
</td>
</tr>
</table>
You need to convert your data. ng-repeat as you have set it up expects an array.
Using some easy code you can get it to an array though, and then your code will work alright.
Also, you should update your html. You don't need to reference items using $index since each item is bound to the iterator variable in that case
<table class="table table-bordered">
<tr>
<th>Classroom</th>
<th>day_1</th>
<th>day_2</th>
</tr>
<tr ng-repeat="roll in rolls">
<td>
{{roll.classroom}}
</td>
<td>
{{roll.day_1}}
</td>
<td>
{{roll.day_2}}
</td>
</tr>
</table>
And then call a convert function that makes the data into an array. I've used lodash.find here, so you either need to reference that or use your own find method.
Rolls.getRollMarked().then(
function(data){
console.log(data.data);
$scope.rolls = convert(data.data);
}
)
function convert(json) {
var rolls = [];
var days = ['day_1', 'day_2'];
for (var d = 0; d < days.length; ++d) {
var day = days[d];
for (var i = 0; i < json[day].length; ++i) {
var classroom = json[day][i];
var existing = _.find(rolls, { "classroom": classroom.classroom });
if (!existing) {
existing = { classroom: classroom.classroom };
rolls.push(existing);
}
existing[day] = classroom.count;
}
}
return rolls;
}

How to sum in each row the values of before rows in specific column?

I've simulated my problem in this fiddle.
I have this HTML:
<table ng-app='Payments'>
<thead>
<tr>
<th>Date</th> <th>Cash</th> <th>Total</th>
</tr>
</thead>
<tbody ng-controller='paymentsController'>
<tr ng-repeat='pay in payments | orderBy : "date"'>
<td>{{pay.date}}</td>
<td><input type="textbox" ng-model="pay.cash"/></td>
<td></td>
</tr>
</tbody>
</table
And this JS:
var appModule = angular.module('Payments', []);
appModule.controller('paymentsController', function($scope) {
$scope.payments = [
{'id' : '1', 'date' : '2015-07-27', 'cash' : '149.98'},
{'id' : '2', 'date' : '2015-07-29', 'cash' : '70.00'},
{'id' : '3', 'date' : '2015-07-27', 'cash' : '129.99'},
{'id' : '4', 'date' : '2015-07-28', 'cash' : '349.90'}
];
});
How do I fill the third column with Angular?
The third column should be initially:
149.98 // due to 0.00 + 149.98
279.97 // due to 149.98 + 129.99
629.87 // due to 279.97 + 349.90
699.87 // due to 629.87 + 70.00
Then, ng-model should do the trick to update them automatically later.
Thanks in advance.
You could add a function to the scope to calculate the total at that index. You have to keep in mind that you are using order by which means you should us the as syntax to calculate the value from the ordered list.
CalculatePay function:
$scope.calculatePay = function(index) {
var sum = 0;
for(var i = 0; i <= index; i++) {
sum += parseFloat($scope.orderedList[i].cash);
}
return sum;
};
html:
<table ng-app='Payments'>
<thead>
<tr>
<th>Date</th> <th>Cash</th> <th>Total</th>
</tr>
</thead>
<tbody ng-controller='paymentsController'>
<tr ng-repeat="pay in payments | orderBy: 'date' as orderedList track by pay.id">
<td>{{pay.date}}</td>
<td><input type="textbox" ng-model="pay.cash"/></td>
<td>{{calculatePay($index)}}</td>
</tr>
</tbody>
</table>
track by is also helpful if the id is truely unique
Example: http://plnkr.co/edit/igBGY1h5RIKMNkncxhp6?p=preview
You would need to handle sorting in code, as the orderBy in ng-repeat creates a new list used for the display, and doesn't modify the original list. This would mean that the indexes of items in the display list don't match up with that in the original list. You'll also need a watcher on the payments collection to automatically update the totals at each position.
Something like
$scope.$watch('payments', function(newPayments) {
$scope.payments = orderByFilter($scope.payments, "date");
$scope.total = 0;
angular.forEach($scope.payments, function(payment) {
$scope.total += parseFloat(payment.cash);
payment.total = $scope.total;
});
}, true);
Fiddle: http://jsfiddle.net/29mh8bfe/4/

Resources