typescript new array with length - arrays

I am using Angular 2 beta and Typescript ("gulp-typescript": "~2.12.1",).
I am writing a component for <div qz-badge num-stars="3" class="qz-badge"></div>
import {Component, Input, ElementRef} from 'angular2/core';
import {CORE_DIRECTIVES} from 'angular2/common';
#Component({
selector: '[qz-badge]',
directives: [CORE_DIRECTIVES],
template: `
<div class="stars">
</div>
`
})
export class Badge {
#Input('num-stars') numStars: number;
constructor() {
console.log(new Array(3));
}
ngOnInit() {
let num = this.numStars;
console.log(num);
console.log('--------');
this.stars = new Array(num);
console.log(this.stars);
console.log(this.stars.length);
num = 3;
console.log('--------');
this.stars = new Array(num);
console.log(this.stars);
console.log(this.stars.length);
}
}
It leads ..
3
--------
["3"]
1
--------
[]
3
In the specification,
Syntax
[element0, element1, ..., elementN]
new Array(element0, element1[, ...[, elementN]])
new Array(arrayLength)
(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
I think the length should be 3.
Is that a bug or is there some righteous reasons?

Actually it's not a bug, it's simply as it works. All #Input()'s are passed as strings. As Rob Wormald's states in this issue.
Types in TS are purely a compile-time construct
So you won't have a number at runtime, but a string, even if you specify number as your Input's type. So you can cast it using parseInt.
// this.numStars is a string, not a number
let num = parseInt(this.numStars);
And that'll make it work correctly.
Here's a plnkr with your case working.
Edit
I missed something in your code. You're passing the value with no binding (no brackets), so it's not getting evaluated. It's a raw string.
The above answer is still valid, but in your case is much easier by passing the value with binding
[num-stars]="3"
Here's another plnkr without the parseInt but using binding.

Related

Property 'paginator' has no initializer and is not definitely assigned in the constructor [duplicate]

in my Angular app i have a component:
import { MakeService } from './../../services/make.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-vehicle-form',
templateUrl: './vehicle-form.component.html',
styleUrls: ['./vehicle-form.component.css']
})
export class VehicleFormComponent implements OnInit {
makes: any[];
vehicle = {};
constructor(private makeService: MakeService) { }
ngOnInit() {
this.makeService.getMakes().subscribe(makes => { this.makes = makes
console.log("MAKES", this.makes);
});
}
onMakeChange(){
console.log("VEHICLE", this.vehicle);
}
}
but in the "makes" property I have a mistake.
I dont know what to do with it...
Just go to tsconfig.json and set
"compilerOptions": {
"strictPropertyInitialization": false,
...
}
to get rid of the compilation error.
Otherwise you need to initialize all your variables which is a little bit annoying
I think you are using the latest version of TypeScript. Please see the section "Strict Class Initialization" in the link.
There are two ways to fix this:
A. If you are using VSCode you need to change the TS version that the editor use.
B. Just initialize the array when you declare it
makes: any[] = [];
or inside the constructor:
constructor(private makeService: MakeService) {
// Initialization inside the constructor
this.makes = [];
}
It is because TypeScript 2.7 includes a strict class checking where all the properties should be initialized in the constructor. A workaround is to add
the ! as a postfix to the variable name:
makes!: any[];
We may get the message Property has no initializer and is not definitely assigned in the constructor when adding some configuration in the tsconfig.json file so as to have an Angular project compiled in strict mode:
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"alwaysStrict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
Indeed the compiler then complains that a member variable is not defined before being used.
For an example of a member variable that is not defined at compile time, a member variable having an #Input directive:
#Input() userId: string;
We could silence the compiler by stating the variable may be optional:
#Input() userId?: string;
But then, we would have to deal with the case of the variable not being defined, and clutter the source code with some such statements:
if (this.userId) {
} else {
}
Instead, knowing the value of this member variable would be defined in time, that is, it would be defined before being used, we can tell the compiler not to worry about it not being defined.
The way to tell this to the compiler is to add the ! definite assignment assertion operator, as in:
#Input() userId!: string;
Now, the compiler understands that this variable, although not defined at compile time, shall be defined at run-time, and in time, before it is being used.
It is now up to the application to ensure this variable is defined before being used.
As an an added protection, we can assert the variable is being defined, before we use it.
We can assert the variable is defined, that is, the required input binding was actually provided by the calling context:
private assertInputsProvided(): void {
if (!this.userId) {
throw (new Error("The required input [userId] was not provided"));
}
}
public ngOnInit(): void {
// Ensure the input bindings are actually provided at run-time
this.assertInputsProvided();
}
Knowing the variable was defined, the variable can now be used:
ngOnChanges() {
this.userService.get(this.userId)
.subscribe(user => {
this.update(user.confirmedEmail);
});
}
Note that the ngOnInit method is called after the input bindings attempt, this, even if no actual input was provided to the bindings.
Whereas the ngOnChanges method is called after the input bindings attempt, and only if there was actual input provided to the bindings.
Go to your tsconfig.json file and change the property:
"noImplicitReturns": false
and then add
"strictPropertyInitialization": false
under "compilerOptions" property.
Your tsconfig.json file should looks like:
{
...
"compilerOptions": {
....
"noImplicitReturns": false,
....
"strictPropertyInitialization": false
},
"angularCompilerOptions": {
......
}
}
Hope this will help !!
Good Luck
The error is legitimate and may prevent your app from crashing. You typed makes as an array but it can also be undefined.
You have 2 options (instead of disabling the typescript's reason for existing...):
1. In your case the best is to type makes as possibily undefined.
makes?: any[]
// or
makes: any[] | undefined
So the compiler will inform you whenever you try to access to makes that it could be undefined.
Otherwise, if the // <-- Not ok lines below were executed before getMakes finished or if getMakes failed, your app would crash and a runtime error would be thrown. That's definitely not what you want.
makes[0] // <-- Not ok
makes.map(...) // <-- Not ok
if (makes) makes[0] // <-- Ok
makes?.[0] // <-- Ok
(makes ?? []).map(...) // <-- Ok
2. You can assume that it will never fail and that you will never try to access it before initialization by writing the code below (risky!). So the compiler won't take care about it.
makes!: any[]
More specifically,
Your code design could be better. Defining a local and mutable variable is generally not a good practice. You should manage data storage inside your service:
firstly to be nullsafe,
secondly to be able to factorise a lot of code (including typing, loading state and errors)
finally to avoid multiple and useless reftech.
The exemple below try to show this but I didn't tested it and it could be improved:
type Make = any // Type it
class MakeService {
private readonly source = new BehaviorSubject<Make[] | undefined>(undefined);
loading = false;
private readonly getMakes = (): Observable<Make[]> => {
/* ... your current implementation */
};
readonly getMakes2 = () => {
if (this.source.value) {
return this.source.asObservable();
}
return new Observable(_ => _.next()).pipe(
tap(_ => {
this.loading = true;
}),
mergeMap(this.getMakes),
mergeMap(data => {
this.source.next(data);
return data;
}),
tap(_ => {
this.loading = false;
}),
catchError((err: any) => {
this.loading = false;
return throwError(err);
}),
);
};
}
#Component({
selector: 'app-vehicle-form',
template: `
<div *ngIf="makeService.loading">Loading...</div>
<div *ngFor="let vehicule of vehicules | async">
{{vehicle.name}}
</div>
`,
styleUrls: ['./vehicle-form.component.css']
})
export class VehicleFormComponent implements OnInit {
constructor(public makeService: MakeService) {}
readonly makes = this.makeService.getMakes2().pipe(
tap(makes => console.log('MAKES', makes))
);
readonly vehicules = this.makes.pipe(
map(make => make/* some transformation */),
tap(vehicule => console.log('VEHICLE', vehicule)),
);
ngOnInit() {
this.makes.subscribe(makes => {
console.log('MAKES', makes);
});
}
}
Update for 2021 :
there is property like "strictPropertyInitialization"
Just go to tsconfig.json and set
"strict": false
to get rid of the compilation error.
Otherwise you need to initialize all your variables which is a little bit annoying.
reason behind this error is :
typescript is a kind of more Secure lang as compare to javascript.
although this security is enhance by enabling strict feature .So every time when you initialize a variable typescript wants them to assign a value.
You either need to disable the --strictPropertyInitialization that
Sajeetharan referred to, or do something like this to satisfy the initialization requirement:
makes: any[] = [];
there are many solutions
demo code
class Plant {
name: string;
// ❌ Property 'name' has no initializer and is not definitely assigned in the constructor.ts(2564)
}
solutions
add 'undefined' type
class Plant {
name: string | undefined;
}
add definite assignment assertion
class Plant {
name!: string;
}
declare with init value πŸ‘
class Plant {
name: string = '';
}
use the constructor with an init value πŸ‘
class Plant {
name: string;
constructor() {
this.name = '';
}
}
use the constructor and init value by params πŸ‘
class Plant {
name: string;
constructor(name: string) {
this.name = name ?? '';
}
}
shorthand of the 5 πŸ‘
class Plant {
constructor(public name: string = name ?? '') {
//
}
}
tsconfig.json
not recommended
{
"compilerOptions": {
+ "strictPropertyInitialization": false,
- "strictPropertyInitialization": true,
}
}
refs
https://www.typescriptlang.org/docs/handbook/2/classes.html#--strictpropertyinitialization
You can also do the following if you really don't want to initialise it.
makes?: any[];
If you want to initialize an object based on an interface you can initialize it empty with following statement.
myObj: IMyObject = {} as IMyObject;
Put a question (?) mark after makes variable.
makes?: any[];
vehicle = {};
constructor(private makeService: MakeService) { }
It should now works.
I'm using angular 12 and it works on my code.
Property '...' has no initializer and is not definitely assigned in the constructor error fix in Angular
Solution 1: Disable strictPropertyInitialization flag
The simple way to fix this error in Angular applications is to disable --strictPropertyInitialization flag in typescript compiler options in tsconfig.json file.
"compilerOptions": {
///
,
"strictPropertyInitialization":false
}
Solution 2: Adding undefined type to the property
It’s ok to have an undefined property.
So while declaring variable add undefined type to the property.
employees: Employee[];
//Change to
employees : Employee[] | undefined;
Solution 3: Add definite assignment assertion to property
If you know that we will assign the property in later point in time.
It’s better to add definite assignment assertion to the property. i.e., employees.
employees!: Employee[];
Solution 4: Add initializer to property
Another way to make this type error go away is to add an explicit initializer to the property.
employees: Employee[] = [];
Solution 5: Assignment in the Constructor
Otherwise, we can assign some default value to the property in the constructor.
employees: Employee[];
constructor() {
this.employees=[];
}
Best Solutions from here
As of TypeScript 2.7.2, you are required to initialise a property in the constructor if it was not assigned to at the point of declaration.
If you are coming from Vue, you can try the following:
Add "strictPropertyInitialization": true to your tsconfig.json
If you are unhappy with disabling it you could also try this makes: any[] | undefined. Doing this requires that you access the properties with null check (?.) operator i.e. this.makes?.length
You could as well try makes!: any[];, this tells TS that the value will be assigned at runtime.
if you don't want to change your tsconfig.json, you can define your class like this:
class Address{
street: string = ''
}
or, you may proceed like this as well:
class Address{
street!: string
}
by adding an exclamation mark "!" after your variable name, Typescript will be sure that this variable is not null or undefined.
A batter approach would be to add the exclamation mark to the end of the variable for which you are sure that it shall not be undefined or null, for instance you are using an ElementRef which needs to be loaded from the template and can't be defined in the constructor, do something like below
class Component {
ViewChild('idname') variable! : ElementRef;
}
in tsconfig.json file , inside "compilerOptions" add :
"strictPropertyInitialization": false,
Get this error at the time of adding Node in my Angular project -
TSError: ? Unable to compile TypeScript:
(path)/base.api.ts:19:13 - error TS2564: Property 'apiRoot
Path' has no initializer and is not definitely assigned in the constructor.
private apiRootPath: string;
Solution -
Added "strictPropertyInitialization": false in 'compilerOptions' of tsconfig.json.
my package.json -
"dependencies": {
...
"#angular/common": "~10.1.3",
"#types/express": "^4.17.9",
"express": "^4.17.1",
...
}
Ref URL - https://www.ryadel.com/en/ts2564-ts-property-has-no-initializer-typescript-error-fix-visual-studio-2017-vs2017/
When you upgrade using typescript#2.9.2 , its compiler strict the rules follows for array type declare inside the component class constructor.
For fix this issue either change the code where are declared in the code or avoid to compiler to add property "strictPropertyInitialization": false in the "tsconfig.json" file and run again npm start .
Angular web and mobile Application Development you can go to www.jtechweb.in
Can't you just use a Definite Assignment Assertion? (See https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#definite-assignment-assertions)
i.e. declaring the property as makes!: any[]; The ! assures typescript that there definitely will be a value at runtime.
Sorry I haven't tried this in angular but it worked great for me when I was having the exact same problem in React.
Another way to fix in the case when the variable must remain uninitialized (and it is dealt with at the run time) is to add undefined to the type (this is actually suggested by VC Code). Example:
#Input() availableData: HierarchyItem[] | undefined;
#Input() checkableSettings: CheckableSettings | undefined;
Depending on actual usage, this might lead to other issues, so I think the best approach is to initialize the properties whenever possible.
a new version of typescript has introduced strick class Initialization, that is means by all of the properties in your class you need to initialize in the constructor body, or by a property initializer. check it in typescript doccumntation
to avoid this you can add (! or ?) with property
make!: any[] or make? : any[]
otherwise, if you wish to remove strick class checking permanently in your project
you can set strictPropertyInitialization": false in tsconfig.json file
"compilerOptions": {
....
"noImplicitReturns": false,
....
"strictPropertyInitialization": false
},
1) You can apply it like the code below. When you do this, the system will not give an error.
"Definite Assignment Assertion" (!) to tell TypeScript that we know this value
Detail info
#Injectable()
export class Contact {
public name !:string;
public address!: Address;
public digital!: Digital[];
public phone!: Phone[];
}
2) The second method is to create a constructor and define values here.
export class Contact {
public name :string;
public address: Address;
public digital: Digital[];
public phone: Phone[];
constructor( _name :string,
_address: Address,
_digital: Digital[],
_phone: Phone[])
{
this.name=_name;
this.address=_address;
this.digital=_digital;
this.phone=_phone;
}
}
3) The third choice will be to create a get property and assign a value as follows
export class Contact {
public name :string="";
public address: Address=this._address;
get _address(): Address {
return new Address();
}
}
In my case it works with different declaration according new typescript strict features:
#ViewChild(MatSort, {static: true}) sort!: MatSort;
If disable typescript new strict feature in tsonfig.json with
"compilerOptions": {
///
,
"strictPropertyInitialization":false
}
the old Angular's guide code works well
#ViewChild(MatSort) sort: MatSort;
Here is 4 ways to solve the issue thanks to
Arunkumar Gudelli (2022) https://www.angularjswiki.com/angular/property-has-no-initializer-and-is-not-definitely-assigned-in-the-constructor/
It is because typescript 2.7.2 included a strict class checking where all properties should be declared in constructor. So to work around that, just add an exclamation mark (!) like:
name!:string;
Add these two line on the tsconfig.json
"noImplicitReturns": true,
"strictPropertyInitialization": false,
and make sure strict is set to true
change the
fieldname?: any[];
to this:
fieldname?: any;
You can declare property in constructor like this:
export class Test {
constructor(myText:string) {
this.myText= myText;
}
myText: string ;
}
This has been discussed in Angular Github at https://github.com/angular/angular/issues/24571
I think this is what everyone will move to
quote from https://github.com/angular/angular/issues/24571#issuecomment-404606595
For angular components, use the following rules in deciding between:
a) adding initializer
b) make the field optional
c) leave the '!'
If the field is annotated with #input - Make the field optional b) or add an initializer a).
If the input is required for the component user - add an assertion in ngOnInit and apply c.
If the field is annotated #ViewChild, #ContentChild - Make the field optional b).
If the field is annotated with #ViewChildren or #ContentChildren - Add back '!' - c).
Fields that have an initializer, but it lives in ngOnInit. - Move the initializer to the constructor.
Fields that have an initializer, but it lives in ngOnInit and cannot be moved because it depends on other #input fields - Add back '!' - c).
JUST go to the tsconfig.ts and add
"strictPropertyInitialization": false, into the compilerOptions Object .
if it doesn't solve yet, kindly re-open your Code Editor.
EXAMPLE:
"compilerOptions" : {
"strictPropertyInitialization": false,
}

Angular 2 ngModel value not updating fast enough using ionic

I have a ion-searchbar that looks like this
<ion-searchbar [(ngModel)]="searchQuery" (keyup.enter)="search();"></ion-searchbar>
and the searchQuery is defined in my typescript file like this
export class SearchPage {
searchQuery: string;
constructor(){}
search() {
this.service.search(this.searchQuery).subscribe(
data => this.searchResults = data,
error => {
//something
}, () => {
//something
}
);
}
}
The problem is that if I change the value too fast and I press Enter, the value of searchQuery is not updated. For example, if I search "test" and I wait two seconds it will work. If I then search "testing" and I type it fast and press Enter right away, the value will still be "test". Now, I know this sounds weird, but it is really happening!
Any ideas why the value is not changed as soon as I type something?
Thank you
In Html try this event change
<form [ngFormModel]="searchForm" (ngSubmit)="search()">
<ion-searchbar [(ngModel)]="searchQuery" (keyup)="search()"></ion-searchbar>
<button type="submit" block>Submit</button>
</form>
Even check here might this help
In ts trim the value
this.service.search(this.searchQuery.trim()).subscribe(.....)
This is how I did it, based on the documentation for ion-searchbar:
<ion-searchbar #searchBar [debounce]="50" (ionChange)="search(searchBar.value)">
</ion-searchbar>
and in the TS file:
search(value: string) {
// do something with value
}
Explanation:
It's pretty self-explanatory, but here it is. The #searchBar creates a 'hook' for the element (sort of a 'self', or 'this', but named). We then use the property value from ion-searchbar to pass it to our function. The last thing is modifying the [debounce] property to make it update faster (but it will trigger more times when people write fast - use with discretion).
Something you can do to improve the way the search bar is being handled is:
In your page.html:
<ion-searchbar primary hideCancelButton [(ngModel)] = "searchQuery" [ngFormControl]="searchQueryControl"></ion-searchbar>
And in your page.ts:
// Remember to import these things:
import {FORM_DIRECTIVES, Control} from 'angular2/common';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
constructor ( ... ) {
//...
this.searchQuery = '';
this.searchQueryControl = new Control();
//...
this.searchQueryControl
.valueChanges
.debounceTime(1000)
.distinctUntilChanged()
.subscribe(text => {
if(text !== '') {
this.searchQuery = text;
this.search();
}
});
//...
}
By doing that, we would only run the code when the input has changed (this.searchQueryControl.valueChanges), and when there hasn't been another change within 1 second (.debounceTime(1000)). The distinctUntilChanged() allow us to run the code if the value is different to the last time it ran. So if the user typed 'asd', hit the backspace key and then retyped the ending 'd' again, nothing would happen.

Angular 2 - Typescript choking on object dot notation, expects ';'

I'm new to TypeScript and Angular 2. I am in the process of moving a project over from Angular 1 and I'm having trouble getting some of my property definitions into the Angular 2 component.
I have these property definitions:
import { Component } from 'angular2/core';
#Component({
selector: 'contact-detail',
templateUrl: 'app/contacts/contact-detail.template.html',
styleUrls: ['app/contacts/contact-detail.style.css']
})
export class ContactDetailComponent {
contactFormOptions = {};
contactFormOptions.initDateDefault = '';
contactFormOptions.followUpDateDefault = '';
contactBasicInfo: {};
contactBasicInfo.bdMonth = '0';
contactBasicInfo.bdDay = '0';
}
Angular 1 was fine with me defining object properties (like contactFormOptions.initDateDefault = '';) this way. With the dot syntax. However, Typescript chokes on the dot notation of those properties and says a ; is expected. Why? What am I missing?
Thanks!
For TypeScript to understand moment.js you need a definition file. Luckily, one is provided with moment.js and you only need to add the reference, which has also been figured out here, at Defintely Typed:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/moment/moment.d.ts
For clarity, what need to be added to the code is:
declare var moment: moment.MomentStatic;
Okay, so it's just me being new to the OOP world. What I needed to do was declare the properties and their types and then assign values within a constructor (or method).
export class ContactDetailComponent {
contactFormOptions: any = {};
contactBasicInfo: any = {};
constructor ( ) {
this.contactFormOptions.initDateDefault = moment();
this.contactFormOptions.followUpDateDefault = moment().add(7, 'days');
this.contactBasicInfo.bdMonth = '0';
this.contactBasicInfo.bdDay = '0';
}
}

Select the text inside an input using Typescript in Angular 2

I'm trying to do exactly what is described in this post, but in Angular2.
Basically use the javascript function .setSelectionRange(start, end); in an input after a user clicks on a trigger. I can't find any way to replicate this behaviour using Typescript.
Thanks in advance.
I can't find any way to replicate this behaviour using Typescript.
TypeScript is just JavaScript. I suspect you mean to say Angular2 (that post is Angular1).
Angular2
You need to get a hold of the dom element (which is what you seem to be struggling with). In your controller you need to inject ElementRef. E.g. #Inject(ElementRef) elementRef: ElementRef,
Once you have the element you can traverse it and do whatever dom access / manual manipulation you need to do.
More
Docs : https://angular.io/docs/js/latest/api/core/ElementRef-class.html
Example
Sample : https://stackoverflow.com/a/32709672/390330
import {Component, ElementRef} from 'angular2/core';
#Component({
selector:'display',
template:`
<input #myname (input) = "updateName(myname.value)"/>
<p> My name : {{myName}}</p>
`
})
class DisplayComponent implements OnInit {
constructor(public element: ElementRef) {
this.element.nativeElement // <- your direct element reference
}
ngOnInit() {
}
}
This example line of code shows the essence of selecting the text (with .name being an ElementRef reference):
this.name.nativeElement.setSelectionRange(0, 999);
Here are all the necessary pieces put together (as well as putting focus on the input) for a "name" field:
View:
<input name="name" formControlName="name" type="text" [(ngModel)]="data.name">
Component:
export class MyComponent {
#ViewChild('name') name: ElementRef; // * see security comment below for ElementRef
#Input() data: {name: 'Foo Baz'};
myForm: FormGroup;
constructor() {
this.myForm = new FormGroup({
name: new FormControl()
});
}
// call this to give the field focus and select its text
focusAndSelectNameFieldText(){
if (!this.name) return;
this.name.nativeElement.focus();
setTimeout(() => {
this.name.nativeElement.setSelectionRange(0, 999);
});
}
}
*Please be sure your use of ElementRef does not pose a security risk:
https://stackoverflow.com/a/44509202/442665

Surprising error message in Angular Dart relating to watchers

I'm writing a component that takes a String and converts it into a list of <span>s. Each <span> gets a String character and is assigned a random color.
The component invocation looks like this:
<span ng-repeat="char in ctrl.chars" style="color: {{ctrl.randomColor}};">
{{char}}
</span>
And the component definition looks like this:
import 'package:angular/angular.dart';
import 'dart:math';
#NgComponent(
selector: 'tokens',
templateUrl: './component.html',
cssUrl: './component.css',
publishAs: 'ctrl',
map: const {
'text' : '#text',
}
)
class TokensComponent {
String text;
List<String> get chars => text.split('');
String get randomColor {
var colors = ['red', 'green', 'yellow', 'blue'];
return colors[new Random().nextInt(colors.length)];
}
}
This works, but generates an error:
5 $digest() iterations reached. Aborting!
Watchers fired in the last 3 iterations:
...
It isn't clear to me just what is being watched here, beyond the getter I am defining.
If I leave the code involving the Random in the getter, but simply return a hard-coded String, the error message goes away.
Any idea what is wrong here?
Binding a getter method with random return value seems like calling for all kind of weird stuff to happen.
From what I see, your intention seems to be to show all characters of a string in a different, random color - but not changing colors (meaning that the characters shouldn't constantly change their color) - is that right?
Unfortunately, the <span> isn't just created with the current return value of randomColor and then forgotten about - binding a property has the advantage that changes to the property are reflected in the view. Of course, since the "property" is a getter and has a random return value, it constantly changes, resulting in constant updates to the view.
If this error wouldn't occur to prevent this endless loop, all characters probably would have the same (rapidly changing) color.
EDIT
This question has a good answer to the problem:
AngularDart custom filter call() method required to be idempotent?
And alternative approach:
ORIGINAL
I'm not sure what you try to achieve but maybe it helps anyway
Screenshot of the result:
library main;
import 'dart:math';
import 'package:angular/angular.dart';
import 'package:di/di.dart';
class MyAppModule extends Module {
MyAppModule() {
type(TokensComponent);
}
}
void main() {
ngBootstrap(module: new MyAppModule());
}
#NgComponent(
selector: 'tokens',
template: '''<span ng-repeat="item in ctrl.items" style="color: {{item.color}};">
{{item.char}}
</span>''',
//cssUrl: './component.css',
publishAs: 'ctrl',
map: const {
'text' : '#text',
}
)
class TokensComponent {
String text = 'abcdefg';
List<Item> items = new List<Item>();
TokensComponent() {
text.split('').forEach((e) => items.add(new Item(e, randomColor)));
}
var colors = \['red', 'green', 'yellow', 'blue'\];
String get randomColor {
return colors\[new Random().nextInt(colors.length)\];
}
}
class Item {
Item(this.char, this.color);
String char;
String color;
}

Resources