I'm fairly new in using Angular. At the moment I'm implementing datatables into a webpage. For that, I'm following this guide: https://l-lin.github.io/angular-datatables/#/basic/server-side-angular-way.
Despite the guide, I gave it my own twist. Resulting in a buggy datatable.
No pagination, all names on one page, data gets lost after searching for a name,..
I make use of forkJoin inside the dtOptions, maybe that's the bug? Anyone got an idea?
My code
export class NewPackageComponent implements OnInit {
dtOptions: DataTables.Settings = {};
pageEvent: PageEvent;
clickedTransactionID: string;
packagesArray: string[]
constructor(public packageToolkitService: PackageToolkitService) { }
ngOnInit(): void {
let that = this;
this.dtOptions = {
pagingType: 'full_numbers',
pageLength: 10,
processing: true,
ajax: (dataTablesParameters: any, callback) => {
forkJoin([that.packageToolkitService.getPackages()])
.subscribe(packages => {
that.packagesArray = packages[0]['packageNames']
})
}
};
}
PackageToolkitService
getPackages() {
return this.http.get(buildUrl('.gui.wmPackage/_get?'), httpOptions);
}
HTML
<table datatable [dtOptions]="dtOptions" class="row-border hover">
<thead>
<tr>
<th>NAME</th>
</tr>
</thead>
<tbody *ngIf="packagesArray?.length != 0">
<tr *ngFor="let package of packagesArray">
<td>{{ package }}</td>
</tr>
</tbody>
<tbody *ngIf="packagesArray?.length == 0">
<tr>
<td colspan="3" class="no-data-available">No data!</td>
</tr>
<tbody>
</table>
JSON GET Response
{
"requestHdrs": {
"Content-Type": "application/json",
},
"packageMap": [
{
"build": "161",
"name": "WmTN",
"description": "Trading Networks",
"version": "10.1.0.0.161"
},
{
"build": "",
"name": "test",
"description": "",
"version": ""
},
{
"name": "be_nrb_rst_shared_party_v2",
"version": "2.0.0"
}
],
"packageNames": [
"WmTN",
"test",
"be_nrb_rst_shared_party_v2"
]
}
Anyone got an idea?
Related
I will need help from someone who is experienced with PayPal Developer. When I make a payment through Sandbox, I only get a receipt of the total price, and not the price of each item. I need to be notified what items my customers will be purchasing.
cart.component.ts
import { Component, OnInit } from '#angular/core';
import { CardsModule } from 'angular-bootstrap-md';
//import { Server } from 'http';
import { CartService } from 'src/app/service/service.service';
import { CheckoutService } from 'src/app/service/checkout.service';
import { HttpClient } from '#angular/common/http';
import { switchMap } from 'rxjs/operators';
import { IPayPalConfig, ICreateOrderRequest } from 'ngx-paypal';
import {render} from 'creditcardpayments/creditCardPayments';
import emailjs, { EmailJSResponseStatus, init } from '#emailjs/browser';
import { isNgTemplate } from '#angular/compiler';
init("user ...");
#Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.scss']
})
export class CartComponent implements OnInit {
public products : any = [];
public grandTotal !: number;
paymentHandler: any = null;
constructor(private cartService : CartService, private http: HttpClient) { }
ngOnInit(): void {
this.cartService.getProducts()
.subscribe(res=>{
this.products = res;
this.grandTotal = this.cartService.getTotalPrice();
})
}
totalItemPayment(quantity: number, price: number){
return quantity * price;
}
removeItem(item: any){
this.cartService.removeCartItem(item);
}
emptycart(){
this.cartService.removeAllCart();
}
checkout(){
const myValue: any = this.grandTotal;
console.log("total price (value) = " + myValue);
let text = JSON.stringify(this.cartService.cartItemList);
var jsonObj = JSON.parse(text);
for(var i = 0; i < jsonObj.length; i++)
{
// tracks the item name, quantity, price in console.log
const description = "quantity: " + jsonObj[i]['quantity'] + "\ntitle: " + jsonObj[i]['title'] + "\n\n";
console.log("item name = " + description);
}
// I would like to find a way to put the item name, quanity, and price in render.
render(
{
id: "#myPaypalButtons",
currency: "USD",
value: myValue,
onApprove: (details) => {
alert("Payment Successful!");
this.emptycart();
}
}
);
}
cart.component.html
<!DOCTYPE html>
<html>
<head>
<script src="https://polyfill.io/v3/polyfill.min.js?version=3.52.1&features=fetch"></script>
</head>
<body>
<ng-container *ngIf="products.length !=0">
<div class="container">
<div class="card-table">
<div class="cart-product">
<table class="table table-responsive">
<thead>
<tr>
<th>Sr.No</th>
<th>Product Name</th>
<th>Product Image</th>
<th>Description</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of products; let i = index">
<td>{{i+1}}</td>
<td>{{item.title}}</td>
<td><img style="width: 40px;" src="{{item.image}}" alt=""></td>
<td style="width: 25%;">{{item.description}}</td>
<th style="width: 12%;">{{item.price}}</th>
<td style="width: 12%;">{{item.quantity}}</td>
<td style="width: 12%;">{{item.price*item.quantity}}</td>
<td>
<button (click)="removeItem(item)" class="btn btn-danger"><i class="fas fa-trash-alt"></i></button>
</td>
</tr>
</tbody>
<p></p>
<br>
<tbody>
<tr>
<td colspan="4"></td>
<td class="a"><button (click)="emptycart()" class="btn btn-danger">Empty Cart</button></td>
<td class="b"><button routerLink="/products" class="btn btn-primary">Shop More</button></td>
<!--<td><button (click)="checkout()">Checkout</button></td>-->
<td class="c"><button (click)="checkout()" class="btn btn-success"> Submit </button></td>
<div id="error-message"></div>
<td class="d"><strong>Total Price = ${{grandTotal}}</strong></td>
</tr>
</tbody>
</table>
<p></p>
<br>
<table>
<div id="myPaypalButtons" class="a"></div>
</table>
</div>
</div>
</div>
<!-- PayPal pop-up, when the "Submit" button gets clicked -->
</ng-container>
<ng-container *ngIf="products.length ==0">
<div class="container">
<div class="card">
<h1 class="card-title">My Cart</h1>
</div>
<div class="center">
<img src="./assets/empty_cart-1200x900.jpg" alt="" style="max-width: 50%;">
<h3>Add item to it now</h3>
<button routerLink="/products" class="btn btn-primary">Shop Now</button>
</div>
</div>
</ng-container>
</body>
</html>
PayPal Developer Request API (Should show line_items, quantity, item_price)
{
"additional_properties": "xxxxxx",
"body": {
"application_context": "xxxxxx",
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": 50
}
}
]
},
"header": {
...
PayPal Developer Response API (Should show line_items, quantity, item_price)
...
"body": {
"create_time": "2022-03-30T14:02:17Z",
"id": "5NF87760A7316650M",
"intent": "CAPTURE",
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/5NF87760A7316650M",
"method": "GET",
"rel": "self"
},
{
"href": "https://www.sandbox.paypal.com/checkoutnow?token=5NF87760A7316650M",
"method": "GET",
"rel": "approve"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/5NF87760A7316650M",
"method": "PATCH",
"rel": "update"
},
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/5NF87760A7316650M/capture",
"method": "POST",
"rel": "capture"
}
],
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "50.00"
},
"payee": {
"email_address": "*****",
"merchant_id": "D89E2QT2Q4MYU"
},
"reference_id": "default"
}
],
"status": "CREATED"
},
...
You don't show where in your implementation the PayPal order is being created. That's where you need to add the item information, inside purchase_units.
You can find an example in the Checkout integration guide, bullet #6 in 'Add and modify the code'
{
"purchase_units": [{
"amount": {
"currency_code": "USD",
"value": "100",
"breakdown": {
"item_total": { /* Required when including the `items` array */
"currency_code": "USD",
"value": "100"
}
}
},
"items": [
{
"name": "First Product Name", /* Shows within upper-right dropdown during payment approval */
"description": "Optional descriptive text..", /* Item details will also be in the completed paypal.com transaction view */
"unit_amount": {
"currency_code": "USD",
"value": "50"
},
"quantity": "2"
},
]
}]
}
//Employee service starts
import {
Injectable
} from "#angular/core";
import {
HttpClient,
HttpErrorResponse
} from "#angular/common/http";
import {
IEmployee
} from "../interfaces/employee";
import {
Observable
} from "rxjs/Observable";
import "rxjs/add/operator/catch";
import "rxjs/add/observable/throw";
#Injectable()
export class EmployeeService {
private _url: string = "assets/data/employee.json";
constructor(private http: HttpClient) {}
getEpmloyees(): Observable < IEmployee[] > {
return this.http.get < IEmployee[] > (this._url).catch(this.errorHandler);
}
errorHandler(error: HttpErrorResponse) {
return Observable.throw(error.message || "Server Error");
}
}
//Employee service end
//-------**********-------*********------**********-------
//Employee component starts
#Component({
selector: "app-employee-details",
templateUrl: "./employee-details.component.html",
styleUrls: ["./employee-details.component.scss"]
})
export class EmployeeDetailsComponent implements OnInit {
public employees = [];
public errorMsg;
constructor(private _employeeService: EmployeeService) {}
ngOnInit() {
this._employeeService.getEpmloyees().subscribe(
data => ((this.employees = data),
error => (this.errorMsg = error)
);
}
}
//Employee component ends
<p>{{errorMsg}}</p>
<table border="1">
<tr>
<th>ID</th>
<th>NAME</th>
<th>AGE</th>
<th>Mobile</th>
<th>Action</th>
</tr>
<tbody *ngFor="let employee of employees">
<tr>
<td>{{employee.id}}</td>
<td>{{employee.name}}</td>
<td>{{employee.age}}</td>
<td>{{employee.mob}}</td>
<td><button>Delete</button></td>
</tr>
</tbody>
</table>
<!--Used JSON data
[
{ "id": 1, "name": "sam", "age": 25, "mob": 9996663752 },
{ "id": 2, "name": "adward", "age": 26, "mob": 9124563712 },
{ "id": 3, "name": "yoshi", "age": 27, "mob": 9246663012 },
{ "id": 4, "name": "casie", "age": 29, "mob": 967663012 }
]
-->
<!-- This data through items object I want to use in above code
{
"items": [
{ "id": 1, "name": "harry", "age": 33, "mob": 3476643752 },
{ "id": 2, "name": "jorge", "age": 54, "mob": 7845633712 },
{ "id": 3, "name": "timon", "age": 65, "mob": 9753833012 },
{ "id": 4, "name": "simon", "age": 43, "mob": 8547763012 }
]
}
-->
Above is my Employee service code and employee's component which is working fine and so here also I have shared my JSON data on how I use second JSON data (which is below the first JSON data) and which is based on "items" object so I am in a situation that what changes do I need to get object base JSON data..?
Try with this.employees = data.items
ngOnInit() {
this._employeeService.getEpmloyees().subscribe(
data => ((this.employees = data.items),
error => (this.errorMsg = error)
);
}
}
Try creating a new interface for the Json data you're gonna retrieve.
interface RootObject {
items: IEmployee[];
}
In your service, get this RootObject and return it to your components.
public getEmployees(): RootObject {
return this.http.get<RootObject>(this._url).catch(this.errorHandler);
}
In your Employee Component, retrieve the array of IEmployees from "items" in the RootObject.
ngOnInit() {
this._employeeService.getEmployees().subscribe(
data => ((this.employees = data.items),
error => (this.errorMsg = error)
);
}
}
Be careful, you misspelled Employees in your service function. You might want to enable spell check in your IDE to avoid mistakes ;)
I generate a JSON with a lot of nested data, one of those properties called 'value' inside 'operations' is used in the v-model of every input of a dynamic generated html table. Initially that property is set to 0 and the input is set with that value but when I change the value in the input it doesn't reflect in the json
The JSON
[
{
"establishment_id":1,
"values":[
{
"capa_id":"A",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
{
"capa_id":"B",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
{
"capa_id":"C",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
]
},
]
The component
Establishments, Operations and CAPA are objects taken from an API via Axios, those data are used to generate the table and the json for the input data
<v-expansion-panels multiple focusable popout class="py-5">
<v-expansion-panel class="expandable" v-for="(establishment, establishmentIndex) in establishments">
<v-expansion-panel-header class="exp_estb">
</v-expansion-panel-header>
<v-expansion-panel-content class="ma-0 pa-0">
<v-row no-gutters>
<v-col cols="12">
<form>
<v-simple-table>
<template>
<thead>
<tr>
<th scope="col">ESTABLECIMIENTO</th>
<th v-for="(operation, index) in operations" scope="col">
{{ operation.description }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(capa, capaIndex) in capas">
<td>{{capa.name}}</td>
<td v-for="(operation, operationIndex) in operations">
<span>{{ operation_data[establishmentIndex].values[capaIndex].operations[operationIndex].value }}</span>
<v-row class="pr-5">
<v-col cols="12" class="mr-2 pr-5">
<v-text-field v-model="operation_data[establishmentIndex].values[capaIndex].operations[operationIndex].value" label="" color="#7F53DD"></v-text-field>
</v-col>
</v-row>
</td>
</tr>
</tbody>
</template>
</v-simple-table>
</form>
</v-col>
</v-row>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
Computed
computed:
{
operation_data: function()
{
let operation_data=[]
let operationsWithContent=[]
let capasWithOperations=[]
var establishments = Object.values(this.establishments)
var capas = Object.values(this.capas)
var operations = Object.values(this.operations)
operations.forEach(operation => operationsWithContent.push({ operation_id:operation.id, value: 0 }))
capas.forEach(capa => capasWithOperations.push({ capa_id:capa.id, operations:operationsWithContent }))
establishments.forEach( establishment => operation_data.push({ id:establishment.id, values:capasWithOperations}) )
return operation_data
}
},
Is there a specific reason you need a computed here? It seems more logical to fetch your data using a method and saving that result in a variable. Then you can assign the variable to the v-model like you already did in your example and it should work out of the box.
data() {
return {
operation_data: null
}
},
mounted() {
this.fetchData();
},
methods: {
fetchData() {
// Get your data here with axios
this.operation_data = resultOfAxios;
}
}
For your question on why the data doesn't reflect back:
A computed is initially just a getter. You have to manually add a setter for the computed for it to be able to update data.
I have json file in a structure (showing one of its objects) as
[
...
{
"Tag": "YearOfOperation",
"Type": 9,
"Value": "2018"
}
...
]
on html template I have a table. On table's "Year Of Operation" row , I want to display "2018". I am trying to iterate over json (i.e find by row/tag name) and display display "Value" of the json. In html template, I want to have something like:
<table>
<tr>
<td> Year Of Operation </td> // row name is hard coded. it doesn't depend on json
<td> display json "Value" where "Tag"=="YearOfOperation" </td>
</tr>
</table>
app.component.ts
public productData: any;
ngOnInit() {
this.getJSON().subscribe(res => {
this.productData = JSON.parse(res);
})
}
public getJSON(): Observable<any> {
return this.http.get('./images/output_test.json')
.pipe(
map(res => res)
)
// .catch((error:any) => console.log(error));
}
Thank you in advance.
If your JSON is something like below and i understood your question correctly, then this is what should work for you:
app.json
[
{ "Tag":"Location", "type": 9, "Value":"Europe" },
{ "Tag":"Location", "type": 10, "Value":"US" },
{ "Tag":"YearOfOperation", "type": 9, "Value":"2016" },
{ "Tag":"YearOfOperation", "type": 10, "Value":"2018" },
{ "Tag":"TaxId", "type": 9, "Value":"txn123" },
{ "Tag":"TaxId", "type": 10, "Value":"txn124" }
]
app.component.html
<table>
<thead><tr><th>Location</th><th>Year Of Operation</th><th>Tax ID</th></tr></thead>
<tbody>
<tr *ngFor="let product of products">
<td *ngIf="product?.Tag === 'Location'; else blankValue">{{product?.Value}}</td>
<td *ngIf="product?.Tag === 'YearOfOperation'; else blankValue">{{product?.Value}}</td>
<td *ngIf="product?.Tag === 'TaxId'; else blankValue">{{product?.Value}}</td>
</tr>
</tbody>
</table>
<ng-template #blankValue><td></td></ng-template>
app.component.ts
public products: any;
ngOnInit() {
this.getJSON().subscribe(res => {
this.products = <Array<{}>>res;
})
}
public getJSON(): Observable<any> {
return this.http.get('./images/output_test.json')
.pipe(
map(res => res),
catchError((error) => { console.error(error); return error;})
);
}
app.component.css
th {
padding:10px;
border:1px solid black;
}
td {
padding:10px;
border:1px solid black;
}
I have the following json data in my application:
{
"Success":true,
"Error":null,
"Data":{
"VersionId":1,
"SecretaryId":1,
"SecretaryName":"Foo",
"Status":1,
"Schools":[
{
"SchoolId":123456,
"SchoolName":"Equipe de Desenvolvimento do Portal",
"ContractStatus":1,
"TotalTeachers":2,
"TotalStudents":0,
"Grades":[
{
"GradeId":1,
"GradeName":"2º Year",
"TotalStudents":0,
"Classes":[
{
"SelectedYear":{
"AvailableYear":null,
"Contract":null,
"Id":2,
"Canceled":false,
"EngagedAreas":null,
"Registrations":null
},
"Id":2,
"Name":"A",
"TotalStudents":20,
"TotalA3":1,
"StudentsPCD":"1,2,3"
},
{
"SelectedYear":{
"AvailableYear":null,
"Contract":null,
"Id":2,
"Canceled":false,
"EngagedAreas":null,
"Registrations":null
},
"Id":3,
"Name":"B",
"TotalStudents":25,
"TotalA3":0,
"StudentsPCD":"1"
}
]
},
{
"GradeId":2,
"GradeName":"3º Year",
"TotalStudents":0,
"Classes":[
]
},
{
"GradeId":3,
"GradeName":"4º Year",
"TotalStudents":0,
"Classes":[
]
}
]
},
{
"SchoolId":52640002,
"SchoolName":"EscTesRelatDir",
"ContractStatus":0,
"TotalTeachers":0,
"TotalStudents":0,
"Grades":[
{
"GradeId":1,
"GradeName":"2º Year",
"TotalStudents":0,
"Classes":[
]
},
{
"GradeId":2,
"GradeName":"3º Year",
"TotalStudents":0,
"Classes":[
]
}
]
}
]
}
}
I use this json to dynamically create some HTML.
For each school a div is created, this is the first level. For each grade in the school, a table is created, this is the second level. And for each class in the grade a table row is created, this is the third level.
I'm wondering how could I use the ng-show command to show the first level div only if the related school have at least one class.
I've searched a lot, but I couldn't find an answer yet.
EDIT:
Here is my html code.
<div ng-repeat="school in data.schools" ng-show="{{ school.Grades.<AnyClass?>.length > 0 }}">
<h2>{{ school.SchoolName }}</h2>
<span><strong>Total Teachers:</strong> {{ school.TotalTeachers }}</span>
<table ng-repeat="grade in school.Grades" class="table table-bordered table-striped table-condensed" ng-show="{{ grade.Classes.length > 0 }}">
<tbody>
<tr>
<th colspan="4">{{ grade.GradeName }}</th>
</tr>
<tr>
<th>Class</th>
<th>Total Students</th>
<th>Total A3</th>
<th>PCD Students</th>
</tr>
<tr ng-repeat="class in grade.Classes">
<td>{{ class.Name }}</td>
<td>{{ class.TotalStudents }}</td>
<td>{{ class.TotalA3 }}</td>
<td>{{ class.StudentsPCD }}</td>
</tr>
</tbody>
</table>
</div>
EDIT
This is how I'm making my requests:
//rest_client.js
"use strict";
(function(){
var restClient = angular.module("restClient", ["ngResource"]);
var serviceURL = "/habileapp/api/";
restClient.factory("RegistrationResource", ["$resource", function ($resource) {
return $resource(serviceURL + "Registration", null, {
"get": {
"method": "get"
},
"save": {
"method": "post",
"url": serviceURL + "Registration/Save"
},
"finalize": {
"method": "post",
"url": serviceURL + "Registration/Finalize"
}
});
}]);
})();
//part of app.js
RegistrationResource.get({
"idAplicacao": 1,
"idSecretaria": 1
}, function (data) {
if (data.Success) {
$scope.data = data.Data;
runApplication();
} else {
toastr.error(Errors.Code1);
}
hideLoading();
});
I don't think it is possible within your template since you cannot bubble up through the different ng-repeats. But you could add another attribute to each school object whether its Classes array length is greater than 0 within your controller:
//part of app.js
RegistrationResource.get({
"idAplicacao": 1,
"idSecretaria": 1
}, function (data) {
if (data.Success) {
angular.forEach(data.Schools, function(item) {
angular.forEach(item.Grades, function(item2) {
(item2.Classes.length > 0) && item.show = true;
});
});
$scope.data = data.Data;
runApplication();
} else {
toastr.error(Errors.Code1);
}
hideLoading();
});
Then, just add ng-show="show" in your markup.
After getting the data you can change it or add any "helper" properties that you can use to control the elements you want to show or how to show them. Consider the following example which makes any entry red that has a "long title", being more than 40 characters:
HTML template
<body ng-controller="Ctrl">
<b><u>Posts</u></b>
<div ng-repeat="post in posts">
<span ng-class="{ 'red': post.longTitle }">
id:{{ post.id }} title:{{ post.title }}
</span>
</div>
</body>
JavaScript
app.controller('Ctrl', function($scope, $http) {
var url = 'http://jsonplaceholder.typicode.com/posts';
// get data
$http.get(url).then(function(response) {
// take top 10
var data = response.data.slice(0, 10);
// add helper property called "long title" that
// doesn't exists in original data
angular.forEach(data, function(current) {
current.longTitle = current.title.length > 40 ? true : false;
});
// apply
$scope.posts = data;
});
});
CSS
.red {
color: red;
}
Result