Giter Club home page Giter Club logo

ng-stack's Introduction

@ng-stack

This Angular library contains two projects:

Related resources

If you love the architectural concepts of Angular and are interested in a backend framework that is very similar to Angular, you can also check out the Ditsmod - new Node.js framework, written in TypeScript.

ng-stack's People

Contributors

dependabot[bot] avatar gabomgp4 avatar kostyatretyak avatar tplk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ng-stack's Issues

Update to Angular 12

Package "@angular-eslint/builder" has an incompatible peer dependency to "@angular/cli" (requires ">= 11.2.0 < 12.0.0", would install "12.0.0").
Package "@ng-stack/api-mock" has an incompatible peer dependency to "@angular/core" (requires ">=4.3.6 <11.0.0" (extended), would install "12.0.0").

fg.hasError('minlength', 'name') error

When i am trying to check a formControl for a 'minlength' error, i am getting this lint error

image

I guess it should be 'minLength', but in this case it does not work.

Bug: "Type 'ExtractModelValue' is not generic" in an Angular v8 project using @ng-stack/forms v2.2.2

I ran into some compiler issues when upgrading ng-stack/forms from 1.3.4 to 2.2.2. So I tried creating a fresh new Angular project and got the same results.
ERROR in node_modules/@ng-stack/forms/lib/form-array.d.ts(6,21): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/form-array.d.ts(7,39): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/form-array.d.ts(85,21): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/form-array.d.ts(122,23): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/form-array.d.ts(181,20): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/input-file.directive.d.ts(7,9): error TS1086: An accessor cannot be declared in an ambient context.
node_modules/@ng-stack/forms/lib/input-file.directive.d.ts(8,9): error TS1086: An accessor cannot be declared in an ambient context.
node_modules/@ng-stack/forms/lib/types.d.ts(81,50): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/types.d.ts(82,19): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/types.d.ts(88,21): error TS2456: Type alias 'ExtractModelValue' circularly references itself.
node_modules/@ng-stack/forms/lib/types.d.ts(88,120): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/types.d.ts(94,21): error TS2315: Type 'ExtractModelValue' is not generic.
node_modules/@ng-stack/forms/lib/types.d.ts(106,72): error TS2315: Type 'ExtractModelValue' is not generic.

AngularStackTest.zip

@ng-stack/forms incompatible with Angular 14

After updating an Angular 13 project with @ng-stack/forms to Angular 14, the following compilation errors appear during the project compilation:


Error: node_modules/@ng-stack/forms/lib/form-builder.d.ts:27:5 - error TS2416: Property 'group' in type 'FormBuilder' is not assignable to the same property in base type 'FormBuilder'.
  Type '<T extends object = any, V extends object = ValidatorsModel>(controlsConfig: { [P in keyof T]: FbControlConfig<T[P], V>; }, options?: AbstractControlOptions<any> | null | undefined) => FormGroup<...>' is not assignable to type '{ <T extends {}>(controls: T, options?: AbstractControlOptions | null | undefined): FormGroup<{ [K in keyof T]: ɵElement<T[K], null>; }>; (controls: { ...; }, options: { ...; }): FormGroup<...>; }'.
    Call signature return types 'FormGroup<any, any>' and 'FormGroup<{ [x: string]: FormControl<unknown>; }>' are incompatible.
      The types of 'controls' are incompatible between these types.
        Type '{ [x: string]: FormGroup<any, any> | FormControl<any, any> | FormArray<any, any>; }' is not assignable to type '{ [x: string]: FormControl<unknown>; }'.
          'string' index signatures are incompatible.
            Type 'FormGroup<any, any> | FormControl<any, any> | FormArray<any, any>' is not assignable to type 'FormControl<unknown>'.
              Type 'FormGroup<any, any>' is missing the following properties from type 'FormControl<unknown>': defaultValue, registerOnChange, registerOnDisabledChange

27     group<T extends object = any, V extends object = ValidatorsModel>(controlsConfig: {
       ~~~~~


Error: node_modules/@ng-stack/forms/lib/form-builder.d.ts:81:5 - error TS2416: Property 'array' in type 'FormBuilder' is not assignable to the same property in base type 'FormBuilder'.
  Type '<Item = any, V extends object = ValidatorsModel>(controlsConfig: FbControlConfig<Item, V>[], validatorOrOpts?: ValidatorFn<any> | ValidatorFn<any>[] | AbstractControlOptions<...> | null | undefined, asyncValidator?: AsyncValidatorFn<...> | ... 2 more ... | undefined) => FormArray<...>' is not assignable to type '<T>(controls: T[], validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null | undefined, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null | undefined) => FormArray<...>'.
    Types of parameters 'controlsConfig' and 'controls' are incompatible.
      Type 'T[]' is not assignable to type 'FbControlConfig<T, ValidationErrors>[]'.
        Type 'T' is not assignable to type 'FbControlConfig<T, ValidationErrors>'.

81     array<Item = any, V extends object = ValidatorsModel>(controlsConfig: FbControlConfig<Item, V>[], validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormArray<Item, V>;
       ~~~~~

Expected:
@ng-stack/forms is compatible with Angular 14.

File input value erased during `change` event

File inputs automatically have an accompanying label that reads "No file chosen". When selecting a single file, the label changes to the name of the file. When selecting multiple files, the label changes to the number of files selected. This is incredibly useful behavior as it provides confirmation to the user that their files were selected. This library forcefully removes the files from the native HTML element at the end of every change event. The result is that the label always reads "No file chosen", even after the user has selected files. The files are still validated and counted as part of the form, but the user has lost that confirmation, and it appears to them that the field is not working at all.

Please remove this instruction, as it only harms user experience. If for some reason it can't be removed, please add an option to preserve the field's native value.

The offending line is

Disabled does not work

Setting control to disabled does nothing, because there is no 'disabled' attribute on HTML Elements that support contenteditable.

Instead, it should remove the contenteditable attr from the host

ng-stack/form (2.2.3) Does not compile when target is es5

I have a webpack based Angular setup and the first time compilation for this module fails with error

Compiling @ng-stack/forms : module as esm5
Error: Error on worker #1: Error: getInternalNameOfClass() called on a non-ES5 class: expected FormBuilder to have an inner class declaration
    at Esm5ReflectionHost.getInternalNameOfClass (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\host\esm5_host.js:88:23)
    at DelegatingReflectionHost.getInternalNameOfClass (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\host\delegating_host.js:89:34)
    at extractInjectableMetadata (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\src\ngtsc\annotations\src\injectable.js:125:69)
    at InjectableDecoratorHandler.analyze (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\src\ngtsc\annotations\src\injectable.js:66:24)
    at NgccTraitCompiler.TraitCompiler.analyzeTrait (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\src\ngtsc\transform\src\compilation.js:345:40)
    at analyze (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\src\ngtsc\transform\src\compilation.js:297:58)
    at _loop_1 (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\src\ngtsc\transform\src\compilation.js:319:21)
    at NgccTraitCompiler.TraitCompiler.analyzeClass (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\src\ngtsc\transform\src\compilation.js:325:35)
    at NgccTraitCompiler.analyzeFile (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\analysis\ngcc_trait_compiler.js:47:26)
    at DecorationAnalyzer.analyzeProgram (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\analysis\decoration_analyzer.js:134:39)
    at ClusterMaster.onWorkerMessage (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\execution\cluster\master.js:194:27)
    at F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\execution\cluster\master.js:54:95
    at ClusterMaster.<anonymous> (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\execution\cluster\master.js:292:57)
    at step (F:\testapp\BOD\testapp.web\ClientApp\node_modules\tslib\tslib.js:141:27)
    at Object.next (F:\testapp\BOD\testapp.web\ClientApp\node_modules\tslib\tslib.js:122:57)
    at F:\testapp\BOD\testapp.web\ClientApp\node_modules\tslib\tslib.js:115:75
    at new Promise (<anonymous>)
    at Object.__awaiter (F:\testapp\BOD\testapp.web\ClientApp\node_modules\tslib\tslib.js:111:16)
    at EventEmitter.<anonymous> (F:\testapp\BOD\testapp.web\ClientApp\node_modules\@angular\compiler-cli\ngcc\src\execution\cluster\master.js:286:32)
    at EventEmitter.emit (events.js:314:20)
F:\testapp\BOD\testapp.Web\ClientApp\node_modules\webpack-cli\bin\cli.js:281
                                throw err;

Here are my tsconfig.json settings

{
  "compileOnSave": true,
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "baseUrl": "./src",
    "lib": [ "ES6","DOM" ],
    "module": "commonjs",
    "moduleResolution": "node",
    "downlevelIteration": true,
    "noImplicitAny": false,
    "importHelpers": true,
    "sourceMap": true,
    "target": "es5",
    "typeRoots": [ "./node_modules/@types" ],
    "paths":{
      "test/*": ["../test/*"],
      "core/*":["./_core/*"],
      "shared/*":["./_shared/*"],
    }
  },
  "include": [ "./src/**/*.ts", "./map/**/*.ts" ],
  "exclude": [ "./node_modules/**/*"],
  "angularCompilerOptions": {
    "fullTemplateTypeCheck": true,
    "strictInjectionParameters": true
  }
}

api-mock: Matching urls with query parameters eg. documents?author="Bob"

For GET queries, parameters are often sent via the url, using parameter queries, e.g youtube links are of the form youtube.com/watch?v=_________

Is it possible to have these urls match the paths before the "?" character?
Example: documents?author=Bob would match the same paths that documents would match?

Right now, I don't need it to do anything automatically, the queryParams collects these parameters perfectly and I'm happy to manually filter or adjust the results myself, I just need a path to be matched so I can read it and use it.

My example:

Right now, I've got a url that looks like documents?author=Bob, but it cannot match path: "documents" or path: "documents/:documentId".

To match it, I've had to explicitly create path: "documents?author=Bob". Inside here, the queryParams object correctly contains {author: "Bob"}, and I can use this inside the responseCallback or dataCallback perfectly, so that part is fine.

Unfortunately this would mean I would need path: "documents?author=Charlie" for example to support a different parameter value, and likewise would a new path for every other possible combination of parameters.

Possible solution

I've stepped through the code and it looks like inside the findRouteIndex function, the value of the url parameter was documents?author=Bob and hence couldn't find a route that matched it (didn't check exactly what it was but this likely meant that partUrl was documents? so couldn't match documents or documents/)

protected findRouteIndex(rootRoutes: PartialRoutes, url: string): number {
for (const rootRoute of rootRoutes) {
// We have `rootRoute.length + 1` to avoid such case:
// (url) `posts-other/123` == (route) `posts/123`
const partUrl = url.substr(0, rootRoute.length + 1);
if (partUrl == rootRoute.path || partUrl == `${rootRoute.path}/`) {
return rootRoute.index;
}
}
return -1;
}

Perhaps it may need to be stripped during the function above, or just before the function is called, eg. between line 185 and 186 below:

protected handleReq(req: HttpRequest<any>): Observable<HttpEvent<any>> {
if (!this.isInited) {
this.init();
}
const normalizedUrl = req.url.charAt(0) == '/' ? req.url.slice(1) : req.url;
const routeIndex = this.findRouteIndex(this.rootRoutes, normalizedUrl);

When it comes to actually doing the stripping of the url, it may be possible to use the urlSerializer.parse function that is already being used elsewhere in the code as shown below. This may have the added benefit of supporting the other types of url parameters that can appear (eg path/matrix parameters). I don't personally need to support these other parameters right now but might be useful to others.

protected getQueryParams(url: string) {
const urlTree = this.urlSerializer.parse(url);
if (!Object.keys(urlTree.queryParams).length) {
return undefined;
}
return urlTree.queryParams;
}

I can try making the changes myself but would need to wait until the weekend to try.

I was using v1.1.0 of the code.

Class constructor FormControl cannot be invoked without 'new'

When testing a component that uses FormControl from @ng-stack/forms I'm getting following error
reproduced in this repo
When used with FormControl from @angular/forms the error is gone.

C:\development\jest-ng-stack-forms-error\jest-error-repo>nx test test-this-lib

> nx run test-this-lib:test

 FAIL   test-this-lib  libs/test-this-lib/src/lib/test-this-component/test-this-component.component.spec.ts
  TestThisComponentComponent
    × should create (27 ms)

  ● TestThisComponentComponent › should create

    TypeError: Class constructor FormControl cannot be invoked without 'new'

       8 | })
       9 | export class TestThisComponentComponent {
    > 10 |   control = new FormControl<string>('init value');
         |             ^
      11 | }
      12 |

      at new FormControl (../../node_modules/projects/forms/src/lib/form-control.ts:42:5)
      at new TestThisComponentComponent (src/lib/test-this-component/test-this-component.component.ts:10:13)
      at NodeInjectorFactory.TestThisComponentComponent_Factory [as factory] (..\..\ng:\TestThisComponentComponent\ɵfac.js:5:10)
      at src/lib/test-this-component/test-this-component.component.spec.ts:17:23

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.362 s
Ran all test suites.

Question

Hey, what's up? We recently wrote a library that takes a similar approach to yours and supports types. Also, we've added reactive queries and more useful methods. I happen to come across your library, and I think that you can add value to the library. Is joining us is something that could interest you?

[Question] why stop publishing to npmjs com ?

Hi,

Subscribing to #77 is fine however I would like to know the reason for it?

I've noticed the latest patches bumping to Angular 11 were missing in my package semver 1.3.0 I installed via npm/yarn2.

@ng-stack/contenteditable: support array of arrays

Using a string as the model works fine.

However, when using an array of arrays as the model, upon entering one character, the contenteditable field loses the focus immediately and no further character can be entered.

<td
        contenteditable="true"
        placeholder="Enter text ..."
        *ngFor="let cell of row; let colIndex = index"
        [(ngModel)]="model[rowIndex][colIndex]"
      >
</td>

Control<T> causes invalid type inference with AbstractControl.value

Control causes invalid type inference with AbstractControl.value

type Person = {
    id: number;
    name: string;
    birthDate: Control<Date>;
}

...

constructor(fb: FormBuilder) {
    const form = fb.group<Person>({
        id: 123,
        name: 'John Smith',
        birthDate: new Date(1977, 6, 30)
    });

    // This results in compile error even though "form.value.birthDate" is a Date
    let birthDate: Date = form.value.birthDate;

    // This compiles but you will always get undefined as your result.
    let birthDate2: Date = form.value.birthDate[0];
}

Type mismatch for FormControl<boolean> initialized with boolean value.

https://stackblitz.com/edit/angular-zqy45b

import { Component, Input } from '@angular/core';
import { FormControl, FormGroup } from '@ng-stack/forms';

interface IEntitlementsForm {
  perpetualLicense: boolean;
}

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  @Input() name: string;
  public perpetualLicense = new FormControl<boolean>(false);
  public formGroup=new FormGroup<IEntitlementsForm>({
    perpetualLicense:this.perpetualLicense
  });
}

Error

Argument of type '{ perpetualLicense: FormControl<boolean, ValidatorsModel>; }' is not assignable to parameter of type '{ perpetualLicense?: FormControl<false, ValidatorsModel> | FormControl<true, ValidatorsModel>; }'.
  Types of property 'perpetualLicense' are incompatible.
    Type 'FormControl<boolean, ValidatorsModel>' is not assignable to type 'FormControl<false, ValidatorsModel> | FormControl<true, ValidatorsModel>'.
      Type 'FormControl<boolean, ValidatorsModel>' is not assignable to type 'FormControl<false, ValidatorsModel>'.
        Type 'boolean' is not assignable to type 'false'.

FormGroup incorrectly extends Angular's FormGroup

How to reproduce:

import { FormControl, FormGroup } from '@ng-stack/forms';

interface ValidationModel {
    wrongPassword?: {returnedValue: boolean};
    wrongEmail?: {returnedValue: boolean};
}
const form = new FormGroup<any> ({
    control: new FormControl<any, ValidationModel>('some value')
});
// error:
// Type 'FormGroup<any, ValidatorsModel> | FormControl<any, ValidatorsModel> | 
// FormArray<any, ValidatorsModel>' is not assignable to type 'AbstractControl'.

This error happens, as FormGroup from @ng-stack/forms extends FormGroup of @angular/forms

On the other hand, this works (as FormControl is used directly from @ng-stack/forms):

import { FormControl } from '@ng-stack/forms';

const control = new FormControl<any, ValidationModel>('some value');

errors in form-group.d.ts:

5: Type 'FormGroup<any, ValidatorsModel> | FormControl<any, ValidatorsModel> | FormArray<any, ValidatorsModel>' is not assignable to type 'AbstractControl'.

39: Property 'registerControl' in type 'FormGroup<T, E>' is not assignable to the same property in base type 'FormGroup'.
  Type '<K extends Extract<keyof T, string>>(name: K, control: ControlType<T[K]>) => ControlType<T[K]>' is not assignable to type '(name: string, control: AbstractControl) => AbstractControl'.
    Types of parameters 'control' and 'control' are incompatible.
      Type 'AbstractControl' is not assignable to type 'ControlType<T[Extract<keyof T, string>]>'.

...

Package versions

@ng-stack/forms: 1.3.0
@angular/forms: 7.0.4

[question] recomendation for single route api?

Hi,

As I have multiple services I want to have multiple fake mock-api endpoints for each.

Problem is all my requests goes tovards single route endpoint (the /api/jsonrpc). Our live servers decides which method you want to call from the POST body key "method".

I had one idea of using httpInterceptor that would modify the endpoint for each method and injects extra route to something like /api/jsonrpc/${call_method} and leave the mock-api to pick up from there. Don't know if it will work well.

The question is if the mock-api would benefit from having an option to "route" request from some other conditions then justgetRoutes(): [{ path: "" }]

Something like

export interface ApiMockReqBodyRoute extends ApiMockRoute {
    reqBodyKey: string; // I always have a requestBody key "method"
    reqBodyKeyValue: string; // and the method varies e.g. "Api.Login", "Api.Ping" ... so on
}

It would do some magic with looping Object.keys to find and compare.

Current interceptor

import { HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Observable } from 'rxjs'

@Injectable({
  providedIn: 'root',
})
export class DemoRouteInterceptor {
  constructor() {}
  intercept(
    req: HttpRequest<unknown>,
    next: HttpHandler,
  ): Observable<HttpEvent<unknown>> {
    if (req.method !== 'POST' || (req.body as any).jsonrpc !== '2.0') {
      return next.handle(req)
    }
    const json_rpc_method = (req.body as any).method
    const demoized_url = `${req.url}/${json_rpc_method}`
    const demoizedReq = req.clone({ url: demoized_url })
    return next.handle(demoizedReq)
  }
}

bug(forms): Issue with interpreting of a validation model

Now not working as expected a validation model. For example, by default used ValidatorsModel:

const formGroup = fb.group({
  userEmail: [null, Validators.required], // Error
  token: [null, Validators.required], // Error
  iAgree: [null, Validators.required], // Error
});

When we passing empty object as validation model, all work as expeced:

const formGroup = fb.group<any, {}>({
  userEmail: [null, Validators.required], // OK
  token: [null, Validators.required], // OK
  iAgree: [null, Validators.required], // OK
});

create FormGroup with field of array type

I want to create a FormGroup with a field that has array type:

interface Data {
  buyer: string;
  action: Control<string[]>;
}

const fb = new FormBuilder();
const filter = fb.Group({
  buyer: '',
  action: new Array<string>()
})

The problem is typescript says that field action is of type string, and not string[], so the asigment is invalid. So, is there a way to use the field action as a FormControl with values of type string[]?

[question] How to debug if mock-api used?

Hi,

I just notice that when I use the fake-api the debugging becomes impossible.

See my two screenshots
This first one is without including the ApiMockModule
2020-04-14 10_41_41-Greenshot

And this is when it is used.
2020-04-14 10_47_03-Greenshot

I am not sure if it happens on your end as well, it happens in all over the stack, variables are "not available".

Using a debugger keyword fails, as it never triggers anywhere.

Why?

[api-mock] Dont make changes if put/post/etc returns a HttpErrorResponse

I'm currently using api-mock for a project, and I've found a lot of stuff I absolutely love about it. However, I recently implemented a PUT operation where I want it to throw errors in certain scenarioes. I implemented a handler for it, and I am able to return an error.

Despite returning an error, the items in my collections gets updated. Any chance this behaviour can be changed, or we can somehow control the updates ourselves with a config flag?

Thanks!

Support string enums?

Hi,

Thank you for creating and sharing this library, it looks very promising.

One issue I've ran into is when having string enums in the model. Is this supported?

Example code:

enum MyStringEnum {
  "VALUEONE" = "VALUEONE",
  "VALUETWO" = "VALUETWO"
}

interface MyInterface {
  fieldOne: string;
  fieldTwo: MyStringEnum;
}

const form = new FormGroup<MyInterface>({
  fieldOne: new FormControl(),
  fieldTwo: new FormControl() // This gives an error 
});

The error I get in my editor (IntelliJ):

Error:(17, 3) TS2322: Type 'FormControl<MyStringEnum, ValidatorsModel>' is not assignable to type 'FormControl<MyStringEnum.VALUEONE, ValidatorsModel> | FormControl<MyStringEnum.VALUETWO, ValidatorsModel>'.
  Type 'FormControl<MyStringEnum, ValidatorsModel>' is not assignable to type 'FormControl<MyStringEnum.VALUEONE, ValidatorsModel>'.
    Type 'MyStringEnum' is not assignable to type 'MyStringEnum.VALUEONE'.

Control type doesn't work with setValue

I have the following form:

    const form = new FormGroup<{
      skills: Control<string[]>
    }>({
      skills: new FormControl(['a', 'b', 'c'])
    });

    form.setValue({ skills: ['1', '2', '3'] })

And I get an error from setValue.

Type 'string[]' is not assignable to type 'Control<string[]>'.   Property '[sym]' is missing in type 'string[]' but required in type 'UniqToken'.

Allow null as initial form control value if the "required" validator is present

Is there maybe a way to automaticly allow null as a initial value even though its not allowed inside the interface? I thought this maybe could be derived from a required validator being preset on the form control.
This problem only occures if typescript is running in strict mode.

Currently I am using the following workaround:

interface FormModel {
    name: string;
}
nullVal: any = null;

constructor(private fb: FormBuilder) {}

createForm(name = null) {
    return this.fb.group<FormModel>({
      name: [name || this.nullVal, [Validators.required]],
    });
}

How to get passThruUnknownUrl: true; working if apiBase is not configurable.

Previously with in memory api I could define single route where the module would interfiere with requests.

    HttpClientInMemoryWebApiModule.forRoot(LoginService, {
      apiBase: 'api/jsonrpc',
      passThruUnknownUrl: true, 
    }),

so I could load static assets json via get from server without issue and only emulate api requests.
now I can only do this sice apiBase is not configurable

    ApiMockModule.forRoot(LoginService, {
      passThruUnknownUrl: true, 
    }),

The I have only Loginservice like this

import { Injectable } from '@angular/core'
import { ApiMockDataCallback, ApiMockRootRoute } from '@ng-stack/api-mock'

@Injectable({
  providedIn: 'root',
})
export class LoginService {
  constructor() {}

  getRoutes(): ApiMockRootRoute[] {
    return [
      {
        path: 'api/jsonrpc',
        dataCallback: this.getDataCallback(),
      },
    ]
  }
 private getDataCallback(): ApiMockDataCallback<any[]> {
    return ({ httpMethod, items }) => {
      if (httpMethod == 'POST') {
        return [{ id: 1, name: 'user1' }]
      } else {
        return items
      }
    }
  }
}

And my frontend fails to load GET /assets/i18n/whatever.json because

ApiMockModule detected wrong route with path "api/jsonrpc".
If you have route.dataCallback, you should to have corresponding a primary key, and vice versa.

I don't understand why it wont let it through.

Guidance on how to support Date in form model

Can you please give guidance on how to support date types for forms?

let type: SomeType{
date: Date
};

this.someForm = new FormGroup({
date: new FormControl()
})

This is not currently supported as a typed form control? Do we use Control or any for SomeType date property?

Is this deprecated with Angular 14?

Hi,

As there're Typed Forms in Angular 14, is @ng-stack/forms library still actual?

Sorry, I don't know much about it, just got a project to upgrade Angular 13 → 14, and it uses @ng-stack/forms, so I wonder whether to work to replace @ng-stack/forms with Angular Typed Forms, or not?

P.S. Also, is there a migration doc for versions 2 → 3 ?

FormGroup in a FromGroup: path error ?

I have a formGroup in a formGroup like this (this is a simplified version):

this.barGoalForm = this.formBuilder.group({
      goalAnnouncement: this.formBuilder.group({
        text: ['']
      })
})

My HTML is:

<div [formControlName]="text" contenteditable="true"></div>

(formGroupName are set in the HTML but you don't see it here)

I have this error:

Cannot find control with path: 'goalAnnouncement -> '

No problem when the div is a textarea.
Can you help me ?

Date should be treated as FormControl, not FormGroup

Type Date should be treated as a FormControl, not a FormGroup.

Ie, I should be able to do this, but it wants establishedDate to be a formGroup:

interface Club {
    id: number;
    name: string;
    isPrimary: boolean;
    establishedDate: Date;
}

…

ngOnInit() {
    const { fb } = this;

    fb.group<Club>({
        id: 1,
        name: 'Whatever',
        isPrimary: true,
        establishedDate: new Date(1988, 1, 1)
    });
}

FormGroup validations model V type parameter is too restrictive.

Fantastic library. But I've hit a bit of a stumbling block.

The validation model type parameter V on FormGroup enforces V on all child controls. The result of this is an entire form must use a single validation model type, rather than something different for each control and/or group. This prohibits easy composability of custom form control components.

For example:

interface SuperValidationErrors {
    notSuper: boolean;
}

interface CoolValidationErrors {
    notCool: boolean;
}

class SuperCool {
    super: string;
    cool: string;
}

formGroup = new FormGroup<SuperCool>({
    super: new FormControl<string, SuperValidationErrors>('', null, (control => {
        return of((control.value === 'syndrome' ? {notSuper: true} : null)).pipe(delay(1000));
    })),
    cool: new FormControl<string, CoolValidationErrors >('', null, (control => {
        return of((control.value !== 'joe' ? {notCool: true} : null)).pipe(delay(1000));
    })),
});

won't compile, as FormGroup defaults V to ValidatorsModel, which enforces V on all child controls.

It can be sort-of tricked to work if you specify FormGroup<SuperCool, SuperValidationErrors | CoolValidationErrors>. This is less than ideal though:

  • the FormGroup type signature grows rapidly, especially if each sub-field has its own validation type. Nested FormGroups become unwieldy.
  • FormControls using the default validation model are no longer compatible, unless something like SuperValidationErrors | CoolValidationErrors | ValidatorsModel is used.
  • formGroup.controls.super.errors now is of type SuperValidationErrors | CoolValidationErrors, preventing property access unless casts are used.

An example error from trying to access the validation model in the template:

Error: src/app/super-cool-form-control/super-cool-form-control.component.ts:40:57 - error TS2339: Property 'notCool' does not exist on type 'SuperValidationErrors | CoolValidationErrors'.
      Property 'notCool' does not exist on type 'SuperValidationErrors'.

<span *ngIf="group.controls.cool.errors.notCool">Invalid: <code>{{group.controls.cool.errors | json}}</code></span>

Bump contenteditable angular peer dependency?

Will the contenteditable library be bumped to Angular 14? I am using it in a V14 project with no apparent issue other than the warning on install that peer dependencies require >=13

Formbuild requires FormGroup on object properties

I have the following interface:

export interface IScheduleForm {
  date:         Date;
  worker:       string;
  service:      string;
  location:     string;
  customer:     Profile;
}

and I wish to implement the form group without make inner forms, because, for example, I just want to give the date Value and do not implement the whole Date form group:

readonly form = this.fb.group<IScheduleForm>({
  location: [null, Validators.required],
  service: [null, Validators.required],
  worker: [null, Validators.required],
  date: [null, Validators.required],
  customer: [null, Validators.required]
});

image

Is there anything I can do so it won't throw any error?

contenteditable: output ignoring new lines

First of all, thank you for your great work!

It seems that the output of the contenteditable directive is ignoring new lines. Is there a property or solution to avoid this?

Thank you for your time.

Wrong peerDependency in api-mock, please bump the semver

I know you fixed the Angular 11 dependency, but the semantic versioning hasn't change, so npmjs.com still contains the unpatched version that has wrong version.

After adding your module

 /frontend/node_modules/@ng-stack/api-mock $ cat package.json | grep peer -A 1
  "peerDependencies": {
    "@angular/core": ">=4.3.6 <11.0.0",
 frontend/node_modules/@ng-stack/api-mock $ cat package.json | grep version
  "version": "1.3.0",

Accessing headers in ApiMock callbacks not possible.

Hi,

Looking through the entire ApiMockResponseCallback interface, there seems to be no request headers.

I see they are that they are being logged:

req: POST http://localhost:4200/api/jsonrpc ...................... ng-stack-api-mock.js:1309:16
{
  "headers": {
    "X-Auth-Token": "+DEMO+rkgdnja5wc3cen55le2y9="
  },
  "body": {
    "id": 1,
    "jsonrpc": "2.0",
    "method": "Api.Ping"
  }
}

but see inside console.login all parameters opts: ApiMockResponseCallbackOptions<any, any>

gives no information about the mentioned headers

{
  "items": [],
  "itemId": "",
  "httpMethod": "POST",
  "parents": [],
  "queryParams": {},
  "reqBody": {
    "id": 1,
    "jsonrpc": "2.0",
    "method": "Api.Ping"
  }
}
@Injectable()
export class ApiMockProxyService implements ApiMockService {
  constructor(private loginService: LoginService) {}

  getRoutes(): ApiMockRootRoute[] {
    return [
      {
        host: new URL(window.location.href).origin,
        path: `api/jsonrpc`,
        responseCallback: this.responseCallback(),
      },
    ]
  }

  responseCallback(): ApiMockResponseCallback {
    return (opts: ApiMockResponseCallbackOptions<any, any>) => {
      switch (opts.reqBody.method) {
        case 'Api.Ping':
          console.log(opts)
   .
   .
   .

Would it make sense to have the headers inside the ApiMockResponseCallbackOptions as well??

Allow FormControl to accept an object

But maybe you want for FormControl to accept an object in its constructor, instead of a primitive value. What to do in this case? At this time, it is not supported. You need to use any type instead.

hi, are there any plans to implement this feature? :)

Pass input `multiple` into the native element

The input attribute multiple is much simpler to use than the HTML native attribute. However, setting [multiple]="true" does not actually allow the user to select multiple files. All the input setting does currently is change the name of the form field in the final result. Please use the value of multiple to add or remove the native attribute to the underlying input.

@Input() multiple: boolean | string;

Nested FormGroup with FormArray type error

I have the following code:

type MyType = { someKey: string[], group: { someNestedKey: string[] } }

new FormGroup<MyType>({
   someKey: new FormArray([]),
   group: new FormGroup({
      someNestedKey: new FormArray([]) <===== FormControl
    })
});

The issue that it infers someNestedKey as FormControl.

Cannot build with Typescript "strict" flag set

Steps to reproduce

  • Use Angular CLI: 7.3.8
  • ng new MyProject
  • cd MyProject
  • npm i @ng-stack/forms
  • add "strict: true" to tsconfig.json
  • import NgStackFormsModule in app.module
  • ng build

Note: Everything is ok if you do not set strict to true.

Here is the error:

ERROR in node_modules/@ng-stack/forms/lib/form-builder.d.ts(26,5): error TS2416: Property 'group' in type 'FormBuilder' is not assignable to the same property in base type 'FormBuilder'.
Type '(controlsConfig: { [P in keyof T]?: FbControlConfig<T[P], V> | undefined; }, options?: AbstractControlOptions | LegacyControlOptions | null | undefined) => FormGroup<...>' is not assignable to type '(controlsConfig: { [key: string]: any; }, options?: AbstractControlOptions | { [key: string]: any; } | null | undefined) => FormGroup'.
Type 'FormGroup<{ [x: string]: ...; }, ValidationErrors>' is not assignable to type 'FormGroup'.
Types of property 'controls' are incompatible.
Type '{ [x: string]: FormGroup<{}, ValidationErrors> | undefined; }' is not assignable to type '{ [key: string]: AbstractControl; }'.
Index signatures are incompatible.
Type 'FormGroup<{}, ValidationErrors> | undefined' is not assignable to type 'AbstractControl'.
Type 'undefined' is not assignable to type 'AbstractControl'.
node_modules/@ng-stack/forms/lib/form-group.d.ts(5,5): error TS2416: Property 'controls' in type 'FormGroup<T, V>' is not assignable to the same property in base type 'FormGroup'.
Type '{ [P in keyof T]?: ControlType<T[P], V> | undefined; }' is not assignable to type '{ [key: string]: AbstractControl; }'.
Type 'ControlType<T[P], V> | undefined' is not assignable to type 'AbstractControl'.
Type 'undefined' is not assignable to type 'AbstractControl'.

@ng-stack/contenteditable - Space Problem (Firefox only)

I'm currently using @ng-stack/contenteditable for a project, and I've found a issue that is happening in Firefox.

Reproduction step:

  • click the mouse cursor before the first word
  • press space two times
  • it set the second space automatically behind the First word (and it set the cursor behind the First word)

Expected behaviour:

  • typing in front of a word doesn't jump over it.

contenteditable: Give a specific directive identifier for the module

Hello,

I've been using this module for a while and it's amazing! However, if there is a certain directive that also can be used with contenteditable and has it's own value accessor, Angular will throw a More than one custom value accessor matches form control with unspecified name attribute error.

Is it possible to change the identifier from [contenteditable][formControl][..] to something like [stack-contenteditable]? Or is it possible to override it somehow?

I tried using [contenteditable]=false, but it didn't work.
Also, the same component is using both modules so I cannot selectively import the modules.

Thank you for your time.

Custom Validators are getting passed the wrong control instance

Checking for foo instanceof FormControl inside a custom validaor returns false if the FormControl is imported from @ng-stack/forms. If it's imported from @angular/forms this will return true.

To reproduce this issue just use the following validator inside your form:

import { AbstractControl, FormControl as FormControlNative } from '@angular/forms';
import { FormControl, ValidatorFn } from '@ng-stack/forms';

export const fooValidator: ValidatorFn = (fc: AbstractControl) => {

  console.log(fc instanceof FormControl); // will be false
  console.log(fc instanceof FormControlNative); // will be true
  
  if (!(fc instanceof FormControl) && !(fc instanceof FormControlNative)) {
    return null;
  }

  return (fc.value as string).indexOf('foo') ? null : { foo: true };
};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.