diff --git a/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts b/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts
index cceba5cfe89b..5b1602c2af36 100644
--- a/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts
+++ b/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts
@@ -14,6 +14,7 @@ describe('StorybookModule', () => {
template: `
{{ input }}
{{ localPropertyName }}
+ {{ setterCallNb }}
{{ localProperty }}
{{ localFunction() }}
@@ -27,6 +28,11 @@ describe('StorybookModule', () => {
@Input('inputBindingPropertyName')
public localPropertyName: string;
+ @Input()
+ public set setter(value: string) {
+ this.setterCallNb += 1;
+ }
+
@Output()
public output = new EventEmitter();
@@ -36,6 +42,8 @@ describe('StorybookModule', () => {
public localProperty: string;
public localFunction = () => '';
+
+ public setterCallNb = 0;
}
it('should initialize inputs', async () => {
@@ -104,6 +112,7 @@ describe('StorybookModule', () => {
it('should change inputs if storyProps$ Subject emit', async () => {
const initialProps = {
input: 'input',
+ inputBindingPropertyName: '',
};
const storyProps$ = new BehaviorSubject(initialProps);
@@ -111,6 +120,7 @@ describe('StorybookModule', () => {
{
storyFnAngular: { props: initialProps },
component: FooComponent,
+
targetSelector: 'my-selector',
},
storyProps$
@@ -150,6 +160,7 @@ describe('StorybookModule', () => {
let expectedOutputValue;
let expectedOutputBindingValue;
const initialProps = {
+ input: '',
output: (value: string) => {
expectedOutputValue = value;
},
@@ -225,6 +236,34 @@ describe('StorybookModule', () => {
expect(fixture.nativeElement.querySelector('p').style.color).toEqual('black');
expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(newProps.input);
});
+
+ it('should call the Input() setter the right number of times', async () => {
+ const initialProps = {
+ setter: 'init',
+ };
+ const storyProps$ = new BehaviorSubject(initialProps);
+
+ const ngModule = getStorybookModuleMetadata(
+ {
+ storyFnAngular: { props: initialProps },
+ component: FooComponent,
+ targetSelector: 'my-selector',
+ },
+ storyProps$
+ );
+ const { fixture } = await configureTestingModule(ngModule);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.querySelector('p#setterCallNb').innerHTML).toEqual('1');
+
+ const newProps = {
+ setter: 'new setter value',
+ };
+ storyProps$.next(newProps);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.querySelector('p#setterCallNb').innerHTML).toEqual('2');
+ });
});
describe('with component without selector', () => {
diff --git a/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts b/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts
index 9192f213f059..a17a54e289fd 100644
--- a/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts
+++ b/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts
@@ -32,7 +32,7 @@ const getNonInputsOutputsProps = (
/**
* Wraps the story template into a component
*
- * @param storyComponent
+ * @param storyComponent //
* @param initialProps
*/
export const createStorybookWrapperComponent = (
@@ -98,39 +98,13 @@ export const createStorybookWrapperComponent = (
this.storyComponentViewContainerRef.injector.get(ChangeDetectorRef).markForCheck();
this.changeDetectorRef.detectChanges();
- // Once target component has been initialized, the storyProps$ observable keeps target component inputs up to date
+ // Once target component has been initialized, the storyProps$ observable keeps target component none Input | Output up to date
this.storyComponentPropsSubscription = this.storyProps$
.pipe(
skip(1),
map((props) => {
- // removes component output in props
- const outputsKeyToRemove = ngComponentInputsOutputs.outputs.map(
- (o) => o.templateName
- );
- return Object.entries(props).reduce(
- (prev, [key, value]) => ({
- ...prev,
- ...(!outputsKeyToRemove.includes(key) && {
- [key]: value,
- }),
- }),
- {} as ICollection
- );
- }),
- map((props) => {
- // In case a component uses an input with `bindingPropertyName` (ex: @Input('name'))
- // find the value of the local propName in the component Inputs
- // otherwise use the input key
- return Object.entries(props).reduce((prev, [propKey, value]) => {
- const input = ngComponentInputsOutputs.inputs.find(
- (o) => o.templateName === propKey
- );
-
- return {
- ...prev,
- ...(input ? { [input.propName]: value } : { [propKey]: value }),
- };
- }, {} as ICollection);
+ const propsKeyToKeep = getNonInputsOutputsProps(ngComponentInputsOutputs, props);
+ return propsKeyToKeep.reduce((acc, p) => ({ ...acc, [p]: props[p] }), {});
})
)
.subscribe((props) => {