I'm the begginer with angular2, and i try to build bootstrap table with nested components, the child component is display in single cell. Probably I'm doing something wrong with ngFor loop. This is my child component:
import { Component, OnInit, ViewEncapsulation, Input } from '#angular/core';
import { Customer } from '../customer';
import { CustomersComponent } from '../customers.component'
#Component({
selector: 'single-customer',
encapsulation: ViewEncapsulation.None,
inputs:['customer'],
templateUrl: './single-customer.component.html',
styleUrls: ['./single-customer.component.css']
})
export class SingleCustomerComponent implements OnInit {
customer: Customer;
constructor() { }
ngOnInit() {
}
}
and template:
<td>
{{customer.surname | uppercase}}
</td>
<td>
{{customer.name}}
</td>
<td>
{{customer.phone}}
</td>
<td>
{{customer.mail}}
</td>
<td>
{{customer.comments}}
</td>
<td><button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target=".update-customer-modal" ng-click="setCustomerData(customer)">Edytuj</button></td>
<td><button type="button" class="btn btn-danger btn-xs" data-toggle="modal" data-target=".delete-customer-modal" ng-click="setCustomerData(customer)">Usuń</button></td>
<!-- </tr> -->
Parent component:
import { Component, OnInit, Directive, ViewEncapsulation } from '#angular/core';
import { NgFor } from '#angular/common';
import { SingleCustomerComponent } from './single-customer/single-customer.component';
import { Customer } from './customer';
import { CustomersService } from './customers.service';
#Component({
selector: 'app-customers',
encapsulation: ViewEncapsulation.None,
templateUrl: './customers.component.html',
styleUrls: ['./customers.component.css'],
providers: [CustomersService],
})
export class CustomersComponent implements OnInit {
customers: Customer[];
customersLength: number;
constructor(private _customersService: CustomersService) {
}
ngOnInit() {
this.getCustomers();
}
getCustomers(){
this._customersService.getCustomers().then((res) => {
this.customers = res;
this.customersLength = this.customers.length;
});
}
}
parent template:
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr class="info">
<td>ID</td>
<td>NAZWISKO</td>
<td>IMIĘ</td>
<td>TELEFON</td>
<td>MAIL</td>
<td>URODZINY</td>
<td>UWAGI</td>
<td></td>
<td></td>
</tr>
</thead>
<tbody>
<tr *ngFor="let customer of customers">
<single-customer [customer]="customer"></single-customer>
</tr>
</tbody>
</table>
</div>
</div>
and parents module:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { CustomersComponent } from './customers.component';
import { SingleCustomerComponent } from './single-customer/single-customer.component'
#NgModule({
imports: [
CommonModule,
],
declarations: [CustomersComponent, SingleCustomerComponent]
})
export class CustomersModule { }
What I'm doing wrong?
Table element in HTML just allows thead, tbody, tfoot and tr as children.
You can change your children component's selector to:
#Component({
selector: '[single-customer]',
...
})
export class SingleCustomerComponent implements OnInit {
...
And change your parent template to:
...
<tbody>
<tr *ngFor="let customer of customers"
single-customer
[customer]="customer">
</tr>
</tbody>
...
Related
I'm using the latest release of vuetify 3 with vue 3, and getting the warning in the title, but optically the table is loading correctly. What might be causing this?
The component containing the table:
<template>
<div class="right-bar text-no-wrap" style="overflow-x: scroll">
<v-simple-table id="myTable">
<template v-slot:default>
<thead>
<tr>
<th class="text-left font-weight-regular">Item</th>
<th class="text-right font-weight-regular font-italic pl-3">Unit</th>
<th class="text-right font-weight-regular pl-3">Total</th>
<th class="text-right font-weight-regular pl-3" v-for="period in dataset.modelPeriods" :key="period">Period {{ period }}</th>
</tr>
</thead>
</template>
</v-simple-table>
</div>
</template>
<script>
import { useStore } from 'vuex'
import { computed } from '#vue/runtime-core'
export default {
setup() {
const store = useStore()
const dataset = computed (
() => store.state.dataset
)
return { dataset }
}
}
</script>
<style>
</style>
My vuetify.js file:
// Styles
import '#mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
// Vuetify
import { createVuetify } from 'vuetify'
export default createVuetify(
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
)
I have the following Vue 3 component that I am using in 2 pages that are setup like this in vue.config.js:
module.exports = {
// Put this in the ASP.NET Core directory
outputDir: "../wwwroot/app",
pages: {
vehicleDetails: "src/VehicleDetails.js",
driverDetails: "src/DriverDetails.js"
}
};
Both of these pages work and share the same underlying 'Certificates' component that looks like this:
<template>
<div>
<h3 id="Vue_Certificates">Certificates</h3>
<div>
objectId: {{objectId}} test
<table class="table table-striped table-hover table-condensed2" style="clear: both;">
<thead>
<tr>
<th><b>test</b></th>
<th style="text-align: right;">
<a href="#" #click="addCertificate">
<i class="fa fa-plus-square"></i> Add
</a>
</th>
</tr>
</thead>
<tbody>
<tr v-for="certificate in certificates" v-bind:key="certificate">
<td>{{ certificate.CertificateTypeId }}</td>
<td>
<a href="#" #click="removeCertificate(index)" title="Delete" style="float: right;" class="btn btn-default">
<i class="fa fa-trash"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import axios from 'axios';
import { onMounted, ref } from "vue";
import $ from 'jquery';
import _ from 'lodash';
export default {
components: {
},
props: {
objectId: String,
ownerIsVehicle: Boolean
},
data() {
return {
certificates: [],
types: []
}
},
created() {
const requestOne = axios.get("/api/v1.0/CertificateType/GetCertificateTypes");
const requestTwo = axios.get("/api/v1.0/Certificate/GetCertificateByObjectId", { params: { objectId: this.objectId, ownerIsVehicle: this.ownerIsVehicle } });
axios.all([requestOne, requestTwo]).then(axios.spread((...responses) => {
const responseOne = responses[0];
const responseTwo = responses[1];
alert("Axios calls completed 1");
this.types = responseOne.data;
var mappedData = responseTwo.data.map(x => ({
...x,
ValidFrom: new Date(x.ValidFrom),
ValidTill: new Date(x.ValidTill)
}));
this.certificates = mappedData;
alert("Axios calls completed 2");
console.log("succes");
})).catch(errors => {
console.log("fail");
});
},
methods: {
removeCertificate(index) {
this.certificates.splice(index, 1);
},
addCertificate() {
alert("Hello?");
}
}
}
</script>
The above code does NOT render the Vue component, but once I take out the two cells containing the anchors that call addCertificate & removeCertificate it all suddenly works.
For some reason I don't get any error in Chrome dev tools .. npm console .. visual studio console .. nowhere, so I have no clue at all what is going wrong.
Important: If I take out 1 of the 2 lines in vue.config.js it works on the page that is still added. The purpose of this component is that it can be reused.
FYI: I shrank down the code as much as possible to make sure other code bits aren't the cause.
For the record, the data property "certificates" was first a ref([]) but that doesn't seem to help at all.
Thanks in advance!
I want to use a material table in my angular application. I went through the official documentation of material to use the table. But I faced several errors in that.
This is my component code:
<div class="container">
<div class="header">
<span style="font-size: 20px;"
>Manage <sub style="font-size: 12px;">Brands</sub></span
>
</div>
<hr style="margin: 10px 0;" />
<button class="btn btn-primary">Add Brand</button>
<br />
<hr />
<cdk-table [dataSource]="dataSource">
<!-- Position Column -->
<ng-container cdkColumnDef="position">
<th cdk-header-cell *cdkHeaderCellDef> No. </th>
<td cdk-cell *cdkCellDef="let element"> {{element.position}} </td>
</ng-container>
<!-- Name Column -->
<ng-container cdkColumnDef="name">
<th cdk-header-cell *cdkHeaderCellDef> Name </th>
<td cdk-cell *cdkCellDef="let element"> {{element.name}} </td>
</ng-container>
<!-- Weight Column -->
<ng-container cdkColumnDef="weight">
<th cdk-header-cell *cdkHeaderCellDef> Weight </th>
<td cdk-cell *cdkCellDef="let element"> {{element.weight}} </td>
</ng-container>
<!-- Symbol Column -->
<ng-container cdkColumnDef="symbol">
<th cdk-header-cell *cdkHeaderCellDef> Symbol </th>
<td cdk-cell *cdkCellDef="let element"> {{element.symbol}} </td>
</ng-container>
<cdk-header-row *cdkHeaderRowDef="displayedColumns"></cdk-header-row>
<cdk-row *cdkRowDef="let row; columns: displayedColumns;"></cdk-row>
</cdk-table>
</div>
This is my imports folder :
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { HeaderComponent } from './header/header.component';
//======================================== material modules==========================
import { MatButtonModule } from '#angular/material/button';
import { MatIconModule } from '#angular/material/icon';
import { MatToolbarModule } from '#angular/material/toolbar';
import { MatInputModule } from '#angular/material/input';
import { MatFormFieldModule } from '#angular/material/form-field'
import { MatDividerModule } from '#angular/material/divider'
import { MatCheckboxModule } from '#angular/material/checkbox';
import { MatSidenavModule } from '#angular/material/sidenav';
import { MatListModule } from '#angular/material/list';
import { CdkTableModule } from '#angular/cdk/table';
import { DataSource } from '#angular/cdk/table'
// ==================================================================================
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { LoginPageComponent } from './login-page/login-page.component';
import { ForgotPasswordPageComponent } from './forgot-password-page/forgot-password-page.component';
import { HomePageComponent } from './home-page/home-page.component';
import { DisplayModule } from './display/display-page.module'
#NgModule({
declarations: [
AppComponent,
HeaderComponent,
LoginPageComponent,
ForgotPasswordPageComponent,
HomePageComponent,
],
imports: [
BrowserModule, AppRoutingModule, BrowserAnimationsModule, MatButtonModule,
MatIconModule, MatToolbarModule,
MatInputModule, MatFormFieldModule, FormsModule, ReactiveFormsModule,
MatDividerModule, MatCheckboxModule, MatSidenavModule, MatListModule,
DisplayModule, CdkTableModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
screenshot of the error
ERROR in src/app/display/brands/brands.component.html:12:3 - error NG8001: 'cdk-table' is not a
known element:
1. If 'cdk-table' is an Angular component, then verify that it is part of this module.
2. If 'cdk-table' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of
this component to suppress this message.
12 <cdk-table [dataSource]="dataSource">
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/display/brands/brands.component.ts:42:16
42 templateUrl: './brands.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component BrandsComponent.
src/app/display/brands/brands.component.html:12:14 - error NG8002: Can't bind to 'dataSource' since
it isn't a known property of 'cdk-table'.
1. If 'cdk-table' is an Angular component and it has 'dataSource' input, then verify that it is part
of this module.
2. If 'cdk-table' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of
this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '#NgModule.schemas' of this component.
12 <cdk-table [dataSource]="dataSource">
~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/display/brands/brands.component.ts:42:16
42 templateUrl: './brands.component.html', ~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component BrandsComponent.
I've already imported all the required modules and using the latest material and angular versions.
Still I can't get that. Can anyone suggest me how to get rid of this error?
Please import matTableModule like below.
import { MatTableModule } from '#angular/material/table'
I am trying to send input data variables from child component form to parent component through dataobject 'data()'. I have seen vuejs update parent data from child component article and tried to do it but, i am unable to $emit captured dataobject through an event. can you please help me out.
Parent component:
<script>
import inputform from '../components/form.vue';
import axios from 'axios';
export default {
name: 'helloword',
data() {
return {
}
},
components: {
inputform
},
methods: {
submit() {
const path = 'http://127.0.0.1:5000';
axios.post(path, {
name: inputform.data()
})
.then(() => {
const result = 'Sucess!';
console.log(result);
})
.catch((error) => {
console.log(error);
})
}
}
}
</script>
Child component:
<template>
<div>
<table>
<thead>
<th>Name</th>
<th>Email</th>
<th>Age</th>
</thead>
<tr>
<td><input type="text" id="name" v-model="details.name" #focusout="inputdata"></td>
<td><input type="text" id="name1" v-model="details.name1" #focusout="inputdata" ></td>
<td><input type="number" id="age" v-model="details.age" #focusout="inputdata" ></td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: "inputform",
data() {
return {
details: {
name: '',
name1: '',
age: ''
}
}
},
methods: {
inputdata() {
this.$emit("input_data", this.details)
}
}
}
</script>
<style scoped>
</style>
So, looking for help with emitting variable data from child compnent to parent and perform submit operation to API using axios from parent component. If there is any other better way please let me know. Thanks.
When attaching a v-model you don't need a v-on. You could also look to capture details into a single object like so and then pass it as part of the event emitted.
Child component
<template>
<div>
<table>
<thead>
<th>Name</th>
<th>Email</th>
<th>Age</th>
</thead>
<tr>
<td>
<input type="text" id="name" v-model="details.name">
</td>
<td>
<input type="email" id="email" v-model="details.email">
</td>
<td>
<input type="number" id="age" v-model="details.age">
</td>
<td>
<button #click="inputdata">Submit</button>
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: "inputform",
data() {
return {
details: {
name: "",
email: "",
age: ""
}
};
},
methods: {
inputdata() {
console.log(this.details);
this.$emit("handledata", this.details);
}
}
};
</script>
Parent component
<template>
<div id="app">
<HelloWorld v-on:handledata="handleInput"/>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld
},
methods: {
handleInput(data) {
// object emitted from the child component
console.log({ data });
}
}
};
</script>
well first you should pass max two params to $emit method here's the docs: https://v2.vuejs.org/v2/api/#vm-emit and second is the v-on: before v-models is extra.
so the solution you can pass this data in one object instead of three data so the code will be like this:
data() {
return {
name: '',
email: '',
age: '',
}
},
methods: {
inputdata() {
this.$emit("input", {
name: this.name,
email: this.email,
age: this.age
})
}
}
or my prefer option put all in a form data like this
<template>
<div>
<table>
<thead>
<th>Name</th>
<th>Email</th>
<th>Age</th>
</thead>
<tr>
<td><input type="text" id="name" v-model="form.name"></td>
<td><input type="email" id="email" v-model="form.email"></td>
<td><input type="number" id="age" v-model="form.age"></td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: "inputform",
data() {
return {
form: {
name: '',
email: '',
age: '',
}
}
},
methods: {
inputdata() {
this.$emit("input", this.form)
}
}
}
</script>
I am unable to use filters with lazy load option. Can anyone help me if i am missing anything here?
I read primeng documentation this and this and this with examples. I could find any solution.
When I use both [lazy] and filters together, filters are not working. If I just remove [lazy]="true" from HTML would work the filters. How can I achieve both?
import { Component, OnInit, Input } from '#angular/core';
import { SelectItem, LazyLoadEvent } from 'primeng/primeng';
import { MyService } from '../services/my.service';
import { ColumnHeaders } from '.';
#Component({
selector: 'myList-table',
templateUrl: 'myList-table.component.html',
styleUrls: ['myList-table.component.less']
})
export class myListTableComponent implements OnInit {
rowCount = { 'value': 5 };
totalRecords: number = 0;
pageNavLinks: number = 0;
myList: any = [];
columnHeaders = ColumnHeaders;
#Input() myListStatus = 'live';
constructor(private myService: MyService) { }
ngOnInit() { this.lazyLoad({ 'first': 0 }); }
lazyLoad(event: LazyLoadEvent) {
const pageNumber = Math.round(event.first / this.rowCount.value) + 1;
this.myService.getmyList(this.myListStatus, pageNumber, this.rowCount.value)
.subscribe(response => {
this.myList = response.batches;
this.totalRecords = response.batches[0].TotalRowCount;
this.pageNavLinks = Math.round(this.totalRecords / this.rowCount.value);
});
}
changeCount() {
this.totalRecords = 0;
this.pageNavLinks = 0;
this.lazyLoad({ 'first': 0 });
}
}
<div class="ui-g-12">
<p-table #dt [columns]="columnHeaders" [value]="myList" [paginator]="true" [rows]="rowCount?.value" [totalRecords]="totalRecords" [responsive]="true" (onLazyLoad)="lazyLoad($event)" [lazy]="true">
<ng-template pTemplate="header" let-columns>
<tr>
<th *ngFor="let col of columns">
{{col.header}}
</th>
</tr>
<tr>
<th *ngFor="let col of columns">
<div class="search-ip-table">
<i class="fa fa-search"></i>
<input pInputText type="text" (input)="dt.filter($event.target.value, col.field, col.filterMatchMode)">
</div>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowData let-columns="columns">
<tr [pSelectableRow]="rowData">
<td>{{rowData.id}}</td>
<td>{{rowData.name}}</td>
<td>{{rowData.TName}}</td>
<td>{{rowData.Base}}</td>
<td>{{rowData.Date | date:'medium' }}</td>
</tr>
</ng-template>
<ng-template pTemplate="paginatorleft">
<span>Total Records: {{totalRecords}}</span>
</ng-template>
<ng-template pTemplate="paginatorright">
<p-dropdown [options]="pageRecordsCountOptions" [(ngModel)]="rowCount" optionLabel="value" (onChange)="changeCount()"></p-dropdown>
</ng-template>
</p-table>
</div>
When [lazy]="true", filter doesn't work in the front-end, but leave this work to the back-end by (onLazyLoad) event.
If you want filter your data in the front-end, you can into lazyLoad() method :
.subscribe(response =>. ...
using filter informations provided by event parameter.