Angular 2 MDL Table model addAll() throws error: Cannot read property 'columns' of undefined - angular2-mdl

I've been following example straight from demo app. Nevertheless, I get an error when using addAll() method to add table data to the model:
Error in ./MdlTableComponent class MdlTableComponent - inline template:7:18 caused by: Cannot read property 'columns' of undefined
Code is below, any insights would be greatly appreciated! (I simplified code and hard-coded table data).
import { Component, OnInit } from '#angular/core';
import {
MdlDialogService, MdlDefaultTableModel, IMdlTableModelItem
} from 'angular2-mdl';
export interface ITableItem extends IMdlTableModelItem {
fname: string;
fsize: number;
ftype: string;
}
#Component({
...
})
export class MyComponent implements OnInit {
public fileListModel: MdlDefaultTableModel = new MdlDefaultTableModel(
[
{ key: 'fname', name: 'File Name' },
{ key: 'fsize', name: 'File Size', numeric: true },
{ key: 'ftype', name: 'File Type' }
]);
public fileListData: [ITableItem] = [
{
fname: 'aaa.png',
fsize: 500,
ftype: 'image/png',
selected: true
}];
ngOnInit(): void {
this.fileListModel.addAll(this.fileListData); // Error is thrown here

Check your corresponding template. It should be using fileListModel
<mdl-table-selectable mdl-shadow="2"
[table-model]="fileListModel"
[table-model-selected]="selected"
(table-model-selectionChanged)="selectionChange($event)">
</mdl-table-selectable>

Related

Using an Abstract class for mutations in NestJS with dynamic input #Args for the update mutation throws type error

Have been working on adding an abstract class to support versioning for Resolvers for a floorPlan feature and was wondering how I might fix this error. At the moment I do not get any Type errors but when the code compiles NestJs throws this error:
Undefined type error. Make sure you are providing an explicit type for the "floorPlanUpdate" (parameter at index [2]) of the "BaseResolverHost" class.
In a normal resolver this is not a problem as you pass in the type e.g.:
#Args('input') input: UpdateFloorPlanV1Input,
However as I am trying to determine the input type based off the version of the Floorplan using this line:
#Args('input') input: UpdateFloorPlanVersion<FloorPlanVersion>,
So it is not possible to explicitly declare it here. Let me know if this is possible or if anyone has any other approaches
This is the abstract Resolver code:
import { Args, Mutation, Query, Resolver } from '#nestjs/graphql';
import { UserId } from 'src/users/decorators/user-id.decorator';
import { CreateFloorPlanInput } from './v1/dto/create-floor-plan.input';
import { UpdateFloorPlanV1Input } from './v1/dto/update-floor-plan.input';
import { FloorPlanV1 } from './v1/models/floor-plan.model';
import { UpdateFloorPlanV2Input } from './v2/dto/update-floor-plan.input';
import { FloorPlanV2 } from './v2/models/floor-plan.model';
export type FloorPlanVersion = FloorPlanV1 | FloorPlanV2;
export type UpdateFloorPlanVersion<T extends FloorPlanVersion> =
T extends FloorPlanV1 ? UpdateFloorPlanV1Input : UpdateFloorPlanV2Input;
export interface FloorPlanServiceInterface<FloorPlanVersion> {
create(
userId: string,
createFloorPlanInput: CreateFloorPlanInput,
): Promise<FloorPlanVersion>;
findOne(userId: string, floorPlanId: string): Promise<FloorPlanVersion>;
update(
userId: string,
floorPlanId: string,
input: UpdateFloorPlanV1Input,
): Promise<FloorPlanVersion>;
}
export function BaseResolver<T extends Type<FloorPlanVersion>>(
classRef: T,
version: string,
) {
#Resolver({ isAbstract: true })
abstract class BaseResolverHost {
floorPlanService: FloorPlanServiceInterface<FloorPlanVersion>;
constructor(readonly service: FloorPlanServiceInterface<FloorPlanVersion>) {
this.floorPlanService = service;
}
#Mutation(() => classRef, { name: `floorPlanCreate${version}` })
async floorPlanCreate(
#UserId() userId,
#Args('input')
input: CreateFloorPlanInput,
) {
return this.floorPlanService.create(userId, input);
}
#Query(() => classRef, { name: `floorPlan${version}` })
async floorPlan(#UserId() userId, #Args('id') id: string) {
return this.floorPlanService.findOne(userId, id);
}
#Mutation(() => classRef, { name: `floorPlanUpdate${version}` })
async floorPlanUpdate(
#UserId() userId,
#Args('id') id: string,
#Args('input') input: UpdateFloorPlanVersion<FloorPlanVersion>,
) {
return this.floorPlanService.update(userId, id, input);
}
}
return BaseResolverHost;
}
And then it is called like this:
#Resolver(() => FloorPlanV2)
export class FloorPlanV2Resolver extends BaseResolver(FloorPlanV2, 'V2') {
constructor(
readonly floorPlanService: FloorPlanService,
) {
super(floorPlanService);
}
}
So if the ObjectType was FloorPlanV2 we would expect the UpdateFloorPlanInputType to be UpdateFloorPlanV2Input

Property component does not exist on type prompto

My issue is I don't know how to fix this. I've looked on other questions similar on this site, and none of them helped.
I have this d.ts:
declare module prompto {
export type PromptoOptions = {
showPreview: boolean,
fileName: string,
outputPath: string,
components: QOptions[]
}
export type QOptions = {
name: string,
type: number
}
export class Prompto {
public addComponents(data: Array<QOptions>): void;
public run(): void;
public showPreview: boolean;
public outputPath: string;
public fileName: string;
public components: QOptions[];
}
}
this is the class:
import PromptoOptions = prompto.PromptoOptions;
import { run } from "../functions/run";
import QOptions = prompto.QOptions;
export class Prompto extends prompto.Prompto {
constructor(options: PromptoOptions = {
showPreview: false,
outputPath: "./",
fileName: "output",
components: []
}) {
super();
this.showPreview = options.showPreview
this.fileName = options.fileName
this.outputPath = options.outputPath
this.components = [];
}
addComponents(arr: Array<QOptions>) {
for (const item of arr) {
if (!item.name || !item.type) {
throw new TypeError("Invalid item")
}
this.components.push(item)
}
}
run() {
console.log(this)
run({ components: this.components })
}
}
and the full error:
src/structures/prompto.ts:17:14 - error TS2551: Property 'components' does not exist on type 'Prompto'. Did you mean 'addComponents'?
17 this.components = [];
~~~~~~~~~~
src/structures/prompto.ts:20:5
20 addComponents(arr: Array<QOptions>) {
~~~~~~~~~~~~~
'addComponents' is declared here.
I just want to fix this. I've been trying to fix this for like 7 hours now. Everywhere I ask no one helps. Just please.
I played around with this in the TS playground and I think that a fix will be to add the line
public components: QOptions[]; before the constructor. Could use a different access modifier (private or protected) if you wanted.
However, I'll also say that I've never seen syntax where you use import with = and in all honesty I've got no idea what effects that might be having on your code.
For trouble shooting this, personally, I would remove the imports and manually write the types I'm expecting to use in the .ts file to check the class is behaving as I want. Then I'd remove those types and import them to check that the imports are behaving as I want.

Problems with ValidationPipe in NestJS when I need to validate the contents of an array

I have a situation where my client user can enter zero or multiple addresses. My problem is that if he enters an address, some fields need to be mandatory.
user.controller.ts
#Post()
#UsePipes(ValidationPipe)
async createUser(
#Body() createUser: CreateUserDto,
) {
return await this.service.saveUserAndAddress(createUser);
}
create-user.dto.ts
export class CreateUserDto {
#IsNotEmpty({ message: 'ERROR_REQUIRED_FULL_NAME' })
fullName?: string;
#IsNotEmpty({ message: 'ERROR_REQUIRED_PASSWORD' })
password?: string;
#IsNotEmpty({ message: 'ERROR_REQUIRED_EMAIL' })
#IsEmail({}, { message: 'ERROR_INVALID_EMAIL' })
email?: string;
...
addresses?: CreateUserAddressDto[];
}
create-user-address.dto.ts
export class CreateUserAddressDto {
...
#IsNotEmpty()
street: string;
...
}
CreateUserDto data is validated correctly and generates InternalServerErrorResponse, but CreateUserAddressDto data is not validated when there is some item in my array. Any idea how I can do this validation?
Nest fw uses class-transformer to convert a json to a class object. You have to set the correct type for the sub-attribute if it is not a primitive value. And your attribute is an array, you have to config to tell class-validator that it is an array, and validate on each item.
Let's update CreateUserDto
import { Type } from 'class-transformer';
import { ..., ValidateNested } from 'class-validator';
export class CreateUserAddressDto {
...
#ValidateNested({ each: true })
#Type(() => CreateUserAddressDto)
addresses?: CreateUserAddressDto[];
...
}
What you are trying to do is - to basically add logic to primitive validators provided out of the box with nest - aka - defining a custom validator.
This can be done by using the two classes ValidatorConstraint and ValidatorConstraintInterface provided by the class validator.
In order to sort this, transform the incoming input / club whatever data you want to validate at once into an object - either using a pipe in nestjs or sent it as an object in the API call itself, then attach a validator on top of it.
To define a custom validator:
import { ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';
/**
* declare your custom validator here
*/
#ValidatorConstraint({ name: 'MyValidator', async: false })
export class MyValidator implements ValidatorConstraintInterface {
/** return true when tests pass **/
validate(incomingObject: myIncomingDataInterface) {
try {
// your logic regarding what all is required in the object
const output = someLogic(incomingObject);
return output;
} catch (e) {
return false;
}
}
defaultMessage() {
return 'Address update needs ... xyz';
}
}
Once you have defined this, keep this safe somewhere as per your project structure. Now you just need to call it whenever you want to put this validation.
In the data transfer object,
// import the validator
import { Validate } from 'class-validator';
import { MyValidator } from './../some/safe/place'
export class SomeDto{
#ApiProperty({...})
#Validate(MyValidator)
thisBecomesIncomingObjectInFunction: string;
}
As simple as that.

Correctly Saving and Updating Entites in Netsjs+TypeORM

I've got a Question regarding TypeORM-Relations and how to use them 'nest-like'.
Suppose I have two Entities defined ChildEntity and TestEntity, which are related.
TestEntity:
import { ChildEntity } from 'src/modules/child-entity/entities/child-entity.entity';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
#Entity()
export class TestEntity {
#PrimaryGeneratedColumn()
id: number;
#Column('varchar')
name: string;
#ManyToOne(() => ChildEntity, (childEntity) => childEntity.testEntities)
childEntity: ChildEntity;
constructor(name: string, childEntity: ChildEntity) {
this.name = name;
this.childEntity = childEntity;
}
}
My first question occurs when I want to create the entity. I have to first translate the passed childEntityId into a ChildEntity, which I can pass to the constructor:
CreateTestEntityDto
import { ApiProperty } from '#nestjs/swagger';
import { IsNotEmpty, IsNumber } from 'class-validator';
export class CreateTestEntityDto {
#ApiProperty()
#IsNotEmpty()
name: string;
#ApiProperty()
#IsNumber()
childEntityId: number;
constructor(name: string, childEntityId: number) {
this.name = name;
this.childEntityId = childEntityId;
}
}
async create(createTestEntityDto: CreateTestEntityDto) {
const { name, childEntityId } = createTestEntityDto;
const childEntity = await this.childEntityService.findOne(childEntityId);
const testEntity = new TestEntity(name, childEntity);
return this.testEntityRepo.save(testEntity);
}
Is there a way to just pass the childEntityId to the save()-Method without explicitly looking for the ChildEntity beforehand?
The Second problem occurs when updating.
UpdateTestEntityDto
import { PartialType } from '#nestjs/swagger';
import { CreateTestEntityDto } from './create-test-entity.dto';
export class UpdateTestEntityDto extends PartialType(CreateTestEntityDto) {}
As updating only a partial Entity is possible I have to check if the Id is even passed along the request and if it is I have to retrieve the correct Entity for the update. Is there a more streamlined way to do this?
async update(id: number, updateTestEntityDto: UpdateTestEntityDto) {
const { name, childEntityId } = updateTestEntityDto;
const props = { name };
if (childEntityId) {
props['childEntity'] = await this.childEntityService.findOne(
childEntityId,
);
}
return this.testEntityRepo.update(id, props);
}
You should add a childEntityId to the test entity:
#Entity()
export class TestEntity {
#PrimaryGeneratedColumn()
id: number;
#Column('varchar')
name: string;
#Column('int')
childEntityId: number;
#ManyToOne(() => ChildEntity, (childEntity) => childEntity.testEntities)
childEntity: ChildEntity;
...
}
and then you can use it to set the id directly. Something like:
async create(dto: Dto) {
const { name, childEntityId } = dto;
const entity = new TestEntity();
entity.name = name;
entity.childEntityId = childEntityId;
return this.testEntityRepo.save(entity);
}
Check this out.
1.) Saving relational entity
There's no need to do all these roundtrips cluttering to save the entity. While, the solution given by #UrosAndelic works but still there's no need to write 3 extra lines of code.
If you hover over a relational param inside the create() method of the repository from an IDE, you'll notice that it accepts two types. First, An Instance of an entity OR Second, a DeepPartial object of an entity.
For instance:
const entity = this.testEntityRepo.create({
name: 'Example 1',
childEntity: {
id: childEntityId // notice: it's a DeepPartial object of ChildEntity
}
})
await this.testEntityRepo.save(entity)
2.) Updating entity
There's no need for child entity's id if you are updating test entity. You can simply update the props of test entity.
const testEntityId = 1;
await this.testEntityRepo.update(testEntityId, {
name: 'Example 2'
})
This will update the name of TestEntity = 1;

Wijmo flexgrid column width angular2

I want Wijmo FlexGrid column width should cover full width.
As I'm dynamically assigning the columns so can't use [width]="'*'"
Assign a template reference variable to the grid. E.g. flex1
<wj-flex-grid #flex1
[itemsSource]="data">
<wj-flex-grid>
Then in the ngAfterViewInit callback set up your columns and assign the column in question the width '*', e.g.
import { Component, ViewChild, AfterViewInit } from '#angular/core';
import { Collection } from 'wijmo/wijmo';
import { FlexGrid } from 'wijmo/wijmo.grid';
#Component({ ... })
export class MyComponent implements AfterViewInit {
#ViewChild('flex1') protected grid: FlexGrid;
protected data: any;
constructor() {
this.data = new Collection([
{ id: 1, country: 'United States' },
{ id: 2, country: 'Germany' },
]);
}
public ngAfterViewInit() {
// Missing part: Set up columns programmatically
// OP has done this already.
// Set the column width of the column with binding to the `country` property
this.grid.columns.getColumn('country').width = '*';
}
}

Resources