tannerntannern / ts-mixer

A small TypeScript library that provides tolerable Mixin functionality.
MIT License
379 stars 27 forks source link

Ts-mixer with Angular #47

Open Nxtivision opened 2 years ago

Nxtivision commented 2 years ago

Hello,

Thank you for this nice library, it seems to be very interesting to use for our use cases.

However, I'm not able to use it properly in Angular. Here is an example :

// Global config for ts-mixer :

import { settings } from 'ts-mixer';

settings.prototypeStrategy = 'proxy';
settings.staticsStrategy = 'proxy';

export default settings;
// Component receiving all extending classes
@Component({
  selector: 'one-forms-input-text',
  templateUrl: './text.component.html',
  styles: [],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: TextComponent,
      multi: true,
    },
  ],
})
export class TextComponent extends Mixin(
  LengthValidatorTemplateMixin,
  ControlValueAccessorConnector
) {
  /**
   * Used to implement a CSS class directly on the host
   * @internal
   * @protected
   */
  @decorate(HostBinding('class.one-forms-input-text'))
  protected override hostClass = true;

  /**
   * Suffix icon to display
   */
  @decorate(Input())
  icon: MaterialIcon = '';

  constructor(injector: Injector) {
    super(injector);
  }
}
export class ControlValueAccessorConnector implements ControlValueAccessor {
  /** Default class applied on Host element */
  @decorate(HostBinding('class.one-forms-input'))
  protected hostClass = true;

  /** Update user-select CSS property */
  @decorate(HostBinding('style.user-select'))
  protected userSelectMode = 'auto';
  /**
   * Used to implement the display CSS property directly on the host
   *
   * @protected
   */
  @decorate(HostBinding('style.display')) protected hostDisplay =
    'inline-block';
  /**
   * @internal
   *
   * used internally to manage the form control
   */
  @decorate(ViewChild(FormControlDirective, { static: true }))
  formControlDirective: FormControlDirective | undefined;

  /**
   * First way to set the formControl by using the formControl itself
   */
  @decorate(Input())
  formControl: FormControl | undefined;

  /**
   * Another way to set the formControl by using the formControlName
   */
  @decorate(Input())
  formControlName = '';

  /**
   * Placeholder of the input, when there is no user input
   */
  @decorate(Input())
  placeholder = '';

  /**
   * Label to name the input
   */
  @decorate(Input())
  label = '';

  /**
   * Add without-label class to the host component if no label specified
   * @protected
   */
  @decorate(HostBinding('class.without-label'))
  protected get hostWithoutLabel() {
    return this.label === '';
  }

  /**
   * The message to describe the input by setting the mat-hint
   */
  @decorate(Input())
  description = '';

  constructor(private injector: Injector) {}
export class LengthValidatorTemplateMixin {
  /**
   * Minimum length for the input
   */
  @decorate(Input()) minLength: string | number | null = null;

  /**
   * Maximum length for the input
   */
  @decorate(Input()) maxLength: string | number | null = null;
}

The error thrown is: Error: Cannot set new properties on Proxies created by ts-mixer

After some investigation, it seems there is a problem with the constructor: 2022-06-21_15h49_28

Do you have any idea how I could use ts-mixer in Angular properly?

Thank you and have a nice day

tannerntannern commented 2 years ago

Hi @Nxtivision, the first thing I'm curious about is whether it's necessary to use ts-mixer's proxy settings in your case. I can't say for certain without doing a deep dive, but I'd guess Angular's dependency injection mechanisms could cause problems with those proxy settings.

Also before I can dive deeper I'll need a minimal reproducible example, preferably as a repository I can clone and recreate the error. There are too many unknowns with your example code (TypeScript/Angular/ts-mixer versions, compilation settings, just to name a few) for me to reproduce or even know for sure whether ts-mixer is the root of the problem.

Please note that I have limited time to support this library, so focused and complete examples are crucial for me to be able to troubleshoot. Thank you for understanding.

hakimio commented 1 year ago

The library works well with the latest version of Angular (14) when you use default prototype strategy.