Is there a way to refresh an Angular component in Storybook using observables or subjects?

When I attempt to update my Angular component using a subject in Storybook by calling subject.next(false), I encounter an issue. The instance property of the component updates, but it does not reflect in the canvas panel.

Here is my loading component:

@Component({
    selector: 'app-loading',
    templateUrl: './loading.component.html'
})
export class LoadingComponent implements OnInit, OnDestory {
    // control the loading icon show or not
    public state: boolean = true;
    private subscription: Subscription = null;

    constructor(private loadingSerivce: LoadingService) {}

    ngOnInit(): void {
        this.subscription = this.loadingService.state.subscribe(state => {
            this.updateState(state);
            console.log(this.state);
        });
    }

    ngOnDestroy(): void {
        if (this.subscription) {
            this.subscription.unsubscribe();
        }
    }

    updateState(state: boolean): void {
        this.state = state;
    }
}

Additionally, here is my loading service:

@Injectable({
    providedIn: 'root'
})
export class LoadingService {
    public state: Subject<boolean> = new Subject<boolean>();
}

And the loading stories configuration:

@Injectable({
    prividedIn: 'root'
})
class MockLoadingService extends LoadingService {
    static instance: MockLoadingService = null;

    constructor() {
        super();

        if (!MockLoadingService.instance) {
            MockLoadingService.instance = this;
        }

        return MockLoadingService.instance;
    } 
}

@Component({
    selector: 'app-loading',
    templateUrl: './loading.component.html',
})
class MockLoadingComponent extends LoadingComponent {
    constructor(private mockLoadingService: MockLoadingService) {
        super(mockLoadingService);
    }
}

export default {
    title: 'Loading',
    component: MockLoadingComponent,
    decorators: [
        moduleMetadata({
            declarations: [MockLoadingComponent],
            providers: [MockLoadingService],
        }),
    ],
} as Meta;

export const Loading: Story = props => ({ props });

Loading.play = async () => {
    await new Promise(resolve => {
        setTimeout(() => {
            MockLoadingService.instance.state.next(false);
            resolve(null);
        }, 2000);
    });
};

My question is: Even after running npm run storybook, the state is updated to false, but the loading icon in the canvas panel remains visible. How can I ensure that the Angular component is updated correctly with observables or subjects in Storybook?


Additional remarks regarding loading.component.html:

<div *ngIf="state" class="loading" id="loading">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="25 25 50 50" class="circular">
        <circle cx="50" cy="50" r="20" fill="none" class="path"></circle>
    </svg>
</div>

Furthermore, the implementation works as expected:

ngOnInit(): void {
    this.subscription = this.loadingService.state.subscribe(state => {
        this.updateState(state);
        console.log(this.state);
    });

    setTimeout(() => {
        this.loadingService.state.next(false);
    }, 1000);
}

However, it does not work as intended within the Storybook play function.

Answer №1

Is your subscription linked to the wrong service? The component is loading an instance of LoadingService and subscribing to it

this.loadingService.state.subscribe

but the next statement is being triggered on an instance of MockLoadingService?

MockLoadingService.instance.state.next(false);

Despite one extending the other, these are not the same services?

Therefore, the solution is to either use MockLoadingService in the component constructor or trigger the next call on the LoadingService class instead of the MockLoadingService class?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Aligning arguments within the function signature

Is it possible to specify in TypeScript that the method 'foo' always expects FooData, etc. for the following code snippet: const search = (data: FooData|BarData|BazData, method:"foo"|"bar"|"baz") => { //Perform some common operations retu ...

What is the best way to locate the position of a different element within ReactJS?

Within my parent element, I have two child elements. The second child has the capability to be dragged into the first child. Upon successful drag and drop into the first child, a callback function will be triggered. What is the best way for me to determi ...

Initially, when an iframe is loaded in Angular 10, it may display a 404 error page

Hey there! I'm currently using the HTML code below to incorporate an iframe and display an external page hosted on the same domain so no need to worry about cross domain issues: <iframe frameborder="0" [src]="url"></iframe ...

Instructions on how to toggle the visibility of a div when hovering over a different a tag

To keep things simple, I'm looking to create a visibility toggle effect on a div when someone hovers over an anchor tag. Similar to the behavior of the four buttons on this example link: The issue I'm facing is that I want the div to appear or b ...

Could JSON be improved for better space efficiency, or is this the standard format?

Within my code, I am using var team = <?php echo json_encode(get_results("SELECT id,name,title,bio,sord,picfn FROM mems ORDER BY sord")); ?>; This code generates a JavaScript array of objects like: var team = [{"id":"1","name":"somename1","title": ...

Monitor the item for fluctuations in its worth

Is there a way to watch an object and wait for all of its values to become truthy? const myObject = { key1: null, key2: null, key3: null, } // Perform asynchronous operations that update myObject const checkValues = async () => { awa ...

Every time I attempt to log into my app, I encounter a persistent 401 error message

I've implemented a user/login route that retrieves a user, compares their password with a hashed version, creates a token, and sends it to the front end. However, I encountered a persistent 401 error in the console on the front end, leading to the fin ...

Tips for incorporating a Python script into a online project

I've been working on a Python code that detects faces and eyes using face recognition. When the code runs in PyCharm, it displays a camera window. Now I'm trying to figure out how to integrate this window into a webpage project written in HTML, C ...

Move on to the following iteration within a (Typescript) .forEach loop by using setTimeout

Within my array, I have a list of image URLs that I need to update the src attribute of an img tag every 10 seconds. To achieve this, I am using a forEach loop which includes a setTimeout function that calls a DOM manipulation function (replaceImage) as sh ...

Can you please provide a detailed list of all the events that are compatible with the updateOn feature in Angular's ngModelOptions?

The reference documentation notes the following: updateOn: a string that specifies which event should be bound to the input. Multiple events can be set using a space delimited list. There is also a special 'default' event that aligns with the ...

What is the best way to show a pop-up model at the bottom of a webpage?

I am working on a project that involves a popup modal that needs to appear after 10 seconds. However, the issue I am facing is that the modal is currently displaying at the top of the page, but I would like it to be shown at the bottom of the page just abo ...

Tips for adjusting the language settings on a date picker

Is there a way to change the language from English to French when selecting a month? I believe I need to configure something in the core.module.ts. How can I achieve this? https://i.sstatic.net/Cpl08.png @NgModule({ declarations: [], imports: [ Co ...

The filter functionality is not functioning properly in AngularJS

Currently, I am working on an AngularJS extension and encountering an issue with the filter functionality. In the popup page of my extension, there is a button. Upon clicking this button, the ancestor node of the button gets blocked, and its relevant info ...

typescript: exploring the world of functions, overloads, and generics

One interesting feature of Typescript is function overloading, and it's possible to create a constant function with multiple overloads like this: interface FetchOverload { (action: string, method: 'post' | 'get'): object; (acti ...

What could be causing my JavaScript loop to replace existing entries in my object?

Recently, I encountered an issue with an object being used in nodejs. Here is a snippet of the code: for(var i = 0; i < x.length; i++) { var sUser = x[i]; mUsers[sUser.userid] = CreateUser(sUser); ++mUsers.length; ...

Adding a Timepicker to a Datepicker on a jsp webpage with javascript

I am working on a JSP page that includes a date picker. I want to enhance this datepicker by adding a start time and end time within the calendar itself. How can I achieve this? Additionally, I need to implement validation ensuring that the start time is a ...

Verify whether a component is a React.ReactElement<any> instance within a child mapping operation

I am facing a challenge with a component that loops through children and wraps them in a div. I want to exclude certain elements from this process, but I am struggling to determine if the child is a ReactElement or not (React.ReactChild can be a string or ...

Dissimilarities in behavior between Angular 2 AOT errors

While working on my angular 2 project with angular-cli, I am facing an issue. Locally, when I build it for production using ng build --prod --aot, there are no problems. However, when the project is built on the server, I encounter the following errors: . ...

`The universal functionality of body background blur is inconsistent and needs improvement.`

I've developed a modal that blurs the background when the modal window is opened. It's functioning flawlessly with one set of HTML codes, but encountering issues with another set of HTML codes (which seems odd considering the identical CSS and Ja ...

A guide on traversing through nested HTML divs using jQuery

I am facing an issue with nested HTML div elements on my website. The data is being fetched from a JSON file and stored in a variable. For example, the 'obj' variable contains an array of objects with properties such as Name, Progress, Descripti ...