Assalmualaikum ..
嗨,大家好。
我正在使用nativescript应用程序。但是我在childComponent上使用ngFor显示的splice
数据数组之后,在更新视图上遇到问题。
问题仅在于splice
。数组push
运作良好。
父组件-> TambahTransaction
关于方法receiveQueue(args)
import { Component, OnInit, NgZone } from "@angular/core";
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
import * as app from "tns-core-modules/application";
import { Page } from "tns-core-modules/ui/page/page";
import { RouterExtensions } from "nativescript-angular/router";
import { TransactionService } from "~/app/shared/services/transaction.service";
import { BarcodeService } from "~/app/shared/services/barcode.service";
import { ActivatedRoute } from "@angular/router";
import { Transaction } from "~/app/shared/models/transaction.model";
import { GoodsTransaction } from "~/app/shared/models/goods-transaction.model";
import { ListGoods } from "~/app/shared/models/list-goods.model";
import { GoodService } from "~/app/shared/services/goods.service";
import { isAndroid } from "tns-core-modules/platform";
import { SearchBar } from "tns-core-modules/ui/search-bar";
import { GridLayout } from "ui/layouts/grid-layout";
import * as Toast from "nativescript-toast";
import { TextField } from "tns-core-modules/ui/text-field";
declare var android: any;
@Component({
selector: "ns-tambah-transaction",
templateUrl: "./tambah-transaction.component.html",
styleUrls: ["./tambah-transaction.component.css"],
moduleId: module.id
})
export class TambahTransactionComponent implements OnInit {
statusKembalian = "Uang Kembali";
isRegistering = false;
isOkToSave = false;
searchPhrase = "";
barangQueue: Array<GoodsTransaction> = [];
transaksi: Transaction = new Transaction();
idToko = "";
listGoodsView: Array<ListGoods> = [];
listGoods: Array<ListGoods> = [];
constructor(
private page: Page,
private routerExtensions: RouterExtensions,
private transactionService: TransactionService,
private barcodeService: BarcodeService,
private activeRoute: ActivatedRoute,
private goodService: GoodService,
private ngZone: NgZone
) {
this.idToko = this.activeRoute.snapshot.paramMap.get("id");
this.transaksi.storeId = this.idToko;
this.transaksi.total = 0;
this.transaksi.createdAt = new Date();
this.transaksi.payment = 0;
this.transaksi.change = 0;
this.transaksi.updatedAt = this.transaksi.createdAt;
this.goodService.getListGoods(this.idToko).subscribe((data) => {
this.listGoods = data;
this.listGoodsView = this.listGoods;
});
this.page.on("loaded, propertyChange, change", (args) => {
const window = app.android.startActivity.getWindow();
window.setSoftInputMode(
android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
);
});
}
ngOnInit() {}
onDrawerButtonTap(): void {
const sideDrawer = <RadSideDrawer>app.getRootView();
sideDrawer.showDrawer();
}
onChangePayment(args) {
const field = <TextField>args.object;
const temp: any = <any>field.text;
this.transaksi.payment = <number>temp;
this.updateTotalBelanja();
}
receiveQueue(args) {
const idxId = this.barangQueue.findIndex((element) => {
return element.goodsId === args.id;
});
console.log("idxId : ", idxId);
if (args.value === null) {
this.barangQueue = this.barangQueue.splice(idxId, 1);
console.log("daftar barang setelah dihapus 1");
console.log(this.barangQueue);
if (this.barangQueue.length > 0) {
this.updateTotalBelanja();
}
} else {
this.barangQueue[idxId] = args.value;
this.updateTotalBelanja();
}
}
updateTotalBelanja() {
const temp = this.barangQueue.reduce((a, b) => {
const t = new GoodsTransaction();
t.totalAfterDisc = a.totalAfterDisc + b.totalAfterDisc;
return t;
});
this.transaksi.total = temp.totalAfterDisc;
this.transaksi.change = this.transaksi.total - this.transaksi.payment;
if (this.transaksi.change > 0) {
this.statusKembalian = "Hutang";
} else {
this.statusKembalian = "Uang Kembali";
}
}
onCancel() {
this.routerExtensions.back();
}
sBLoaded(args) {
const searchbar: SearchBar = <SearchBar>args.object;
if (isAndroid) {
searchbar.android.clearFocus();
}
}
onClear(args) {
const searchBar = <SearchBar>args.object;
searchBar.text = "";
searchBar.dismissSoftInput();
}
onTextChanged(args) {
const searchBar = <SearchBar>args.object;
this.searchPhrase = searchBar.text;
this.pencarian();
}
pencarian() {
if (this.searchPhrase === "") {
this.listGoodsView = this.listGoods;
} else {
this.listGoodsView = this.listGoods.filter((data) => {
if (
data.name.toLowerCase().includes(this.searchPhrase.toLowerCase()) ||
data.barcode.includes(this.searchPhrase)
) {
return data;
}
});
}
}
onItemTap(args, item) {
console.log("item tapped");
console.log(item);
const grid = <GridLayout>args.object;
setTimeout(() => {
grid.className = "list-group-item on-list-tapped";
}, 0);
setTimeout(() => {
grid.className = "list-group-item";
}, 150);
const cekDuplicate = this.barangQueue.findIndex((element) => {
return element.goodsId === item.id;
});
if (cekDuplicate === -1) {
const queue = new GoodsTransaction();
queue.goodsId = item.id;
queue.barcode = item.barcode;
queue.name = item.name;
queue.sellingPrice = item.sellingPrice;
queue.quantity = 1;
queue.discOnSellingPrice = 0;
queue.totalPrice =
(queue.sellingPrice - queue.discOnSellingPrice) * queue.quantity;
queue.discOntotalPrice = 0;
queue.totalAfterDisc = queue.totalPrice - queue.discOntotalPrice;
queue.createdAt = new Date();
queue.updatedAt = queue.createdAt;
this.barangQueue.push(queue);
} else {
this.barangQueue[cekDuplicate].quantity++;
this.barangQueue[cekDuplicate].totalPrice =
(this.barangQueue[cekDuplicate].sellingPrice -
this.barangQueue[cekDuplicate].discOnSellingPrice) *
this.barangQueue[cekDuplicate].quantity;
this.barangQueue[cekDuplicate].totalAfterDisc =
this.barangQueue[cekDuplicate].totalPrice -
this.barangQueue[cekDuplicate].discOntotalPrice;
}
this.updateTotalBelanja();
console.log("antrian barang");
console.log(this.barangQueue);
this.searchPhrase = "";
}
onItemLongPress(args, item) {
const grid = <GridLayout>args.object;
setTimeout(() => {
grid.className = "list-group-item on-list-tapped";
}, 0);
setTimeout(() => {
grid.className = "list-group-item";
}, 100);
this.routerExtensions.navigate([
"goods/" + this.idToko + "/detailBarang",
item.id
]);
}
onScan() {
this.barcodeService
.scanBarcode()
.then((bar) => {
console.log(bar, "ini bar");
this.searchPhrase = bar;
this.pencarian();
})
.catch((err) => {
Toast.makeText(err).show();
});
}
async onSave() {}
}
这是TambahTransaction的视图
<ActionBar class="action-bar" title="">
<NavigationButton ios:visibility="collapsed" icon="res://menu" (tap)="onDrawerButtonTap()"></NavigationButton>
<ActionItem icon="res://navigation/menu" android:visibility="collapsed" (tap)="onDrawerButtonTap()" ios.position="left">
</ActionItem>
<Label class="action-bar-title" text="Tambah Transaksi"></Label>
</ActionBar>
<DockLayout class="page page-content" stretchLastChild="true">
<StackLayout dock="bottom">
<ListView height="160" [items]="listGoodsView" class="list-group daftar-barangku" *ngIf="listGoods.length > 0 && searchPhrase!== ''">
<ng-template let-dataitem="item" let-i="index">
<GridLayout columns="*,2*,*" rows="*,*,*" class="list-group-item " (tap)="onItemTap($event, dataitem)"
(longPress)="onItemLongPress($event, dataitem)">
<Label [text]="dataitem.barcode" col="0" row="0" colSpan="2" textWrap="true" class="list-barcode"></Label>
<Label [text]="dataitem.name" col="0" row="1" colSpan="3" textWrap="true" class="list-nama-barang"></Label>
<Label [text]="dataitem.note" col="0" colspan="1" row="2" textWrap="true" class="list-note"></Label>
<Label [text]="'Rp. '+ dataitem.sellingPrice" col="2" row="2" textWrap="true" class="list-harga"></Label>
</GridLayout>
</ng-template>
</ListView>
<FlexboxLayout flexDirection="row" justifyContent="center">
<SearchBar #pencarian hint="Cari Barang" (loaded)="sBLoaded($event)" [text]="searchPhrase" (textChange)="onTextChanged($event)"
(clear)="onClear($event)"></SearchBar>
</FlexboxLayout>
<FlexboxLayout class="input-field" flexWrap="wrap" flexDirection="row" alignItems="center" justifyContent="space-between">
<Button class="btn btn-warn" text="Cancel" (tap)="onCancel()" [isEnabled]="!isRegistering"></Button>
<Button class="btn btn-warn" text="Scan" (tap)="onScan()" [isEnabled]="!isRegistering"></Button>
<Button class="btn btn-primary" text="Save" (tap)="onSave()" [isEnabled]="!isRegistering && isOkToSave"></Button>
</FlexboxLayout>
</StackLayout>
<ScrollView sdkExampleTitle sdkToggleNavButton>
<StackLayout *ngIf="barangQueue.length > 0">
<StackLayout *ngFor="let item of barangQueue">
<Label [text]="item"></Label>
<ns-daftar-transaction (queueEvent)="receiveQueue($event)" [queue]="item"></ns-daftar-transaction>
</StackLayout>
<GridLayout columns="*,2*,2*,2*" rows="*,*,*" class="list-transaction m-b-10 m-t-5">
<Label text="Total Bayar" textWrap="true" col="1" colspan="2" row="0"></Label>
<Label [text]="'Rp. '+transaksi.total" col="3" row="0"></Label>
<Label text="Uang Pembayaran" textWrap="true" col="1" colspan="2" row="1"></Label>
<TextField class="tf-uang-bayar" col="3" row="1" keyboardType="number" [text]="transaksi.payment"
(textChange)="onChangePayment($event)"></TextField>
<Label [text]="statusKembalian" textWrap="true" col="1" colspan="2" row="2"></Label>
<Label [text]="'Rp. '+transaksi.change" col="3" row="2"></Label>
</GridLayout>
</StackLayout>
</ScrollView>
</DockLayout>
这是子组件-> DaftarTransaction
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
import { GoodsTransaction } from "~/app/shared/models/goods-transaction.model";
import { Goods } from "~/app/shared/models/goods.model";
import { GoodService } from "~/app/shared/services/goods.service";
import { Button } from "tns-core-modules/ui/button";
import { TextField } from "tns-core-modules/ui/text-field";
@Component({
selector: "ns-daftar-transaction",
templateUrl: "./daftar-transaction.component.html",
styleUrls: ["./daftar-transaction.component.css"],
moduleId: module.id
})
export class DaftarTransactionComponent implements OnInit {
dataBarang: Goods = null;
@Input() queue: GoodsTransaction;
@Output() queueEvent = new EventEmitter<{
id: string;
value: GoodsTransaction;
}>();
constructor(private goodService: GoodService) {}
ngOnInit() {
console.log("constructor daftar transaksi");
console.log(this.queue);
this.goodService
.getGoods(this.queue.goodsId)
.then((data) => {
this.dataBarang = data;
})
.catch((err) => {
console.log("gagal mendapatkan barang id : ", this.queue.goodsId);
console.log(err);
});
}
onChangePrice(args) {
const btn = <Button>args.object;
if (btn.className === "btn-ecer") {
btn.className = "btn-grosir";
this.queue.sellingPrice = this.dataBarang.sellingPriceGrosir;
} else {
btn.className = "btn-ecer";
this.queue.sellingPrice = this.dataBarang.sellingPrice;
}
this.onUpdateQueue();
}
onDeleteQueue() {
this.queue = null;
this.queueEvent.emit({ id: this.queue.goodsId, value: this.queue });
}
onUpdateQueue() {
this.queue.totalPrice =
(this.queue.sellingPrice - this.queue.discOnSellingPrice) *
this.queue.quantity;
this.queue.totalAfterDisc =
this.queue.totalPrice - this.queue.discOntotalPrice;
this.queueEvent.emit({ id: this.queue.goodsId, value: this.queue });
}
onChangeDiscOnSellingPrice(args) {
const field = <TextField>args.object;
const temp: any = <any>field.text;
this.queue.discOnSellingPrice = <number>temp;
this.onUpdateQueue();
}
onChangeDiscOnTotalPrice(args) {
const field = <TextField>args.object;
const temp: any = <any>field.text;
this.queue.discOntotalPrice = <number>temp;
this.onUpdateQueue();
}
onChangeQuantity(args) {
const field = <TextField>args.object;
const temp: any = <any>field.text;
this.queue.quantity = <number>temp;
this.onUpdateQueue();
}
}
这是DaftarTransaction的视图
<GridLayout columns="*,2*,2*,2*" rows="*,*,*,*,*" class="list-transaction">
<Button text="x" col="3" row="0" class="btn btn-del-goods" horizontalAlignment="right" (tap)="onDeleteQueue()"></Button>
<TextField [text]="queue.quantity" class="tf-quantity m-l-5" maxLength="3" col="0" row="1" keyboardType="number" (textChange)="onChangeQuantity($event)"></TextField>
<Label [text]="queue.name" textWrap="true" col="1" colspan="2" row="1"></Label>
<Label [text]="'Rp. '+queue.totalAfterDisc" col="3" row="1"></Label>
<Button verticalAlignment="bottom" text="*" class="btn-ecer" col="0" row="2" (tap)="onChangePrice($event)"></Button>
<Label [text]="'Rp. '+queue.sellingPrice" col="1" row="2"></Label>
<Label [text]="'Rp. '+queue.totalPrice" col="2" row="2"></Label>
<Label text="Diskon" col="0" row="3"></Label>
<TextField class="tf-discount" col="1" row="3" keyboardType="number" (textChange)="onChangeDiscOnSellingPrice($event)"></TextField>
<TextField class="tf-discount" col="2" row="3" keyboardType="number" (textChange)="onChangeDiscOnTotalPrice($event)"></TextField>
<Label [text]="'Rp. '+ (queue.sellingPrice-queue.discOnSellingPrice)" col="1" row="4"></Label>
</GridLayout>
我做splice
后遇到的错误是这样的:
idxId : 1
JS: ERROR TypeError: Cannot read property 'goodsId' of null
JS: ERROR CONTEXT {
JS: "view": {
JS: "def": {
JS: "nodeFlags": 1,
JS: "rootNodeFlags": 1,
JS: "nodeMatchedQueries": 0,
JS: "flags": 0,
JS: "nodes": [
JS: {
JS: "nodeIndex": 0,
JS: "parent": null,
JS: "renderParent": null,
JS: "bindingIndex": 0,
JS: "outputIndex": 0,
JS: "checkIndex": 0,
JS: "flags": 1,
JS: "childFlags": 1,
JS: "directChildFlags": 1,
JS: "childMatchedQueries": 0,
JS: "matchedQueries": {},
JS: "matchedQueryIds": 0,
JS: "references": {},
JS: "ngContentIndex": null,
JS: "childCount": 11,
JS: "bindings": [],
JS: "bindingFlags": 0,
JS: "outputs": [],
JS: "element": {
JS: "ns": "",
JS: "name": "GridLayout",
JS: "attrs": [
JS: [
JS: "",
JS: "class",
JS: "list-transaction"
JS: ],
JS: [
JS: "",
JS: "columns",
JS: "*,2*,2*,2*"
JS: ],
JS: [...
JS: ERROR TypeError: Cannot read property 'quantity' of null
JS: ERROR CONTEXT {
JS: "view": {
JS: "def": {
JS: "nodeFlags": 1,
JS: "rootNodeFlags": 1,
JS: "nodeMatchedQueries": 0,
JS: "flags": 0,
JS: "nodes": [
JS: {
JS: "nodeIndex": 0,
JS: "parent": null,
JS: "renderParent": null,
JS: "bindingIndex": 0,
JS: "outputIndex": 0,
JS: "checkIndex": 0,
JS: "flags": 1,
JS: "childFlags": 1,
JS: "directChildFlags": 1,
JS: "childMatchedQueries": 0,
JS: "matchedQueries": {},
JS: "matchedQueryIds": 0,
JS: "references": {},
JS: "ngContentIndex": null,
JS: "childCount": 11,
JS: "bindings": [],
JS: "bindingFlags": 0,
JS: "outputs": [],
JS: "element": {
JS: "ns": "",
JS: "name": "GridLayout",
JS: "attrs": [
JS: [
JS: "",
JS: "class",
JS: "list-transaction"
JS: ],
JS: [
JS: "",
JS: "columns",
JS: "*,2*,2*,2*"
JS: ],
JS: [...
大家有什么解决办法吗?
如果您对我使用的代码/逻辑提出建议,我将不胜感激。