"Even after firing the observable through an event, the Async pipe continues to return null

I am currently working with an angular component that incorporates a rich text editor (tiptap v2) and displays the corresponding JSON output. I have created an observable from the update event provided by the editor, aiming to initialize the editor with mock data. My expectation was for the editor to trigger an update event, leading to the correct display of JSON data. However, this does not work after initialization, as the async pipe returns null. Although I found a workaround using the rxjs startWith operator, it feels odd to initialize the observable separately from the editor it should observe.

Below is my template:

<div class="editor-window">
  <tiptap-editor [editor]="editor"></tiptap-editor>
</div>

<div style="margin-top: 15px">
  <b>JSON</b><br />
  <pre style="overflow: scroll">{{ editorJson$ | async | json }}</pre>
  <mat-divider></mat-divider>
</div>

Additionally, here is the corresponding component setup:

import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { Editor } from '@tiptap/core';
import { StarterKit } from '@tiptap/starter-kit';
import { fromEvent, Observable, startWith } from 'rxjs';
import { dummyContent } from './dummy-content';

@Component({
  selector: 'nai-annotation-editor',
  templateUrl: './annotation-editor.component.html',
  styleUrls: ['./annotation-editor.component.scss'],
  encapsulation: ViewEncapsulation.None,
})
export class AnnotationEditorComponent implements OnInit, OnDestroy {
  public editor: Editor;

  // Register editor 'update event' as observable
  public editorJson$: Observable<any> | undefined;

  constructor() {
    this.editor = new Editor({
      extensions: [
        StarterKit.configure({
          heading: {
            levels: [1, 2, 3],
          },
          blockquote: false,
          code: false,
          codeBlock: false,
          horizontalRule: false,
          strike: false,
        }),
      ],
    });
  }

  ngOnInit(): void {
    this.editorJson$ = fromEvent(this.editor, 'update', (event) =>
      event?.editor.getJSON()
    ); //.pipe(startWith(dummyContent));
    this.editor.commands.setContent(dummyContent, true);
  }

  ngOnDestroy(): void {
    this.editor.destroy();
  }
}

Moving the editor.commands.setContent(...) to ngAfterViewInit() results in the expected display, but triggers an

ExpressionChangedAfterItHasBeenChecked
Error.

Despite confirming that the observable indeed returns a value through subscription and console.log output, why is it not being displayed by the async pipe?

My suspicion falls on the component lifecycle and usage of the async pipe, but I lack certainty...

Answer №1

It's a fact that you can function perfectly fine without needing observable:

export class NoteEditorComponent implements OnInit, OnDestroy {
  public editor: Editor;

  public editorData$: any;

  constructor() {
    this.editor = new Editor({
      extensions: [
        StarterKit.configure({
          // includes support for up to three heading levels
          heading: {
            levels: [1, 2, 3],
          },
          // unnecessary extensions are turned off
          blockquote: false,
          code: false,
          codeBlock: false,
          horizontalRule: false,
          strike: false,
        }),
      ],
    });
    this.editor.on('update', (event) => {
        this.editorData$ = event?.editor.getJSON();
    });
    this.editor.commands.setContent(dummyContent, true);
  }

  ngOnDestroy(): void {
    this.editor.destroy();
  }
}

<div class="note-window">
  <note-editor [editor]="editor"></note-editor>
</div>

<div style="margin-top: 15px">
  <b>EDITOR DATA</b><br />
  <pre style="overflow: scroll">{{ editorData$ | json }}</pre>
  <mat-divider></mat-divider>
</div>

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

Structure of an Ionic 2 project (visuals)

When working on an Ionic 2 project, where should I store my images? Some sources suggest placing them in www\build\"images_folder", however, the issue arises when you build the project or use the command: ionic serve. This process removes and reb ...

Is it possible to dynamically alter the background color of a box in Material UI using TypeScript when clicked?

I need a way to change the background color of my Box when it is clicked. I have searched for a solution but couldn't find anything that fits my needs. I tried using onClick events, but haven't found the right event to get information on the sele ...

What is the best way to integrate cross-env with Expo?

I'm currently working on an expo app and hoping to integrate cross-env with it. To make this possible, I modified the start script in package.json to "cross-env LOCAL_IP_ADDRESS=TEST expo start", but unfortunately, the environment variable ...

Issues with the functionality of the asynchronous socket.io JavaScript callback are being experienced

I am facing an issue with my JavaScript code that involves querying data from a database using Node.js and Socket.io. Currently, I have implemented setTimeout() functions to make it work, but I want to switch to using callbacks for better reliability. Howe ...

Resolve Conflict Between Chrome Debugger and Node App in Visual Studio Code

My current configuration in the launch.json file within Visual Studio Code looks like this: { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Launch Progra ...

Acquiring the assigned class attribute

I have an image that triggers ajax requests when clicked. To pass a variable from $_GET[] to my onclick function, I came up with the following solution: <img id="img1" class="<?=$_GET['value']"?> /> and using jQue ...

ngStyle isn't being correctly implemented

I've encountered an issue in my Angular 5 application where [ngStyle] is not translating to the style attribute as expected. Instead, I only see ng-reflect-ng-style in the generated HTML. This functionality was working fine before. Could there have be ...

The Twilio client encounters resolution issues when incorporating it with Bun

There is a verification check function implemented as follows: async verifyWithOTP(phone: string, otp: string) { console.log({ phone, otp }); try { console.log("awaiting verification"); const verification = await client.verify.v2 ...

Searching for getStaticPaths using a GROQ query that involves nested dynamic routing

My NextJS project has a complex nested folder structure. You can view the layout here. Utilizing Sanity as my CMS, the getStaticPaths function within my index.js file is functioning properly: export const getStaticPaths = async () => { const routes ...

Is there a way to ensure that fields in a sub component are validated whenever we attempt to switch the Tab using a route

Hi there, I could really use your assistance. I've done some research, but I haven't been able to find a suitable solution for my problem. I have this shared component that contains the following code which enables tab navigation through various ...

Is it advisable to solely rely on CDN for incorporating Bootstrap JS components, or are there any potential drawbacks to

I'm in the process of customizing Bootstrap using my own styles, by utilizing a local version of the source SASS files as outlined in the official documentation, and importing them into a custom.scss file. My main focus is on altering the visual aspe ...

Losing Selected Value in AngularJS Dropdown After REST API Call and Updating Scope Variable

My development setup includes an AngularJS front end paired with an ASP.net Web API backend. Currently, I have a select list implementation utilizing the code snippet below: <select id="package" class="form-control" ng-options="package as package.Name ...

What is the best approach to return an Observable value only if it is not null, otherwise invoke an HTTP service to fetch and return the

@Injectable() /*** * Profile Management Service */ export class ManageProfileService { private userDetails: any = null; public getUserDetails$: Observable<any> } I am attempting to subscribe to the GetUserDetails Observable from this se ...

Encountering ExpressionChangedAfterItHasBeenCheckedError in Angular 17 even after invoking detectChanges method

I'm encountering a minor problem with Angular and its change detection mechanism. I have created a simple form where additional input fields can be added dynamically. However, every time I click the add button, an ExpressionChangedAfterItHasBeenChecke ...

What techniques can be used to create a more streamlined progress bar in coding?

Adding a progress bar has been a bit tricky for me - sometimes it fills too slowly or too quickly, but for the most part, it works fine. I believe there must be a more efficient way to program this since my current method involves too many calculations fo ...

What steps should be taken to incorporate that dynamic sliding element (like a sliding screen paper) on the webpage?

When hovering over the leftmost part of the homepage at www.techants.com, a box shifts to the foreground. I examined the code and noticed a reference to something called screen paper. Does anyone know which script is being used for this effect? How can I ...

Exploring the concepts of angularjs $apply and $scope within the context of object manipulation

In nearly every software application, there is a necessity to modify objects. In my scenario, I have a list of objects that can be edited on the fly with the help of Angular. However, this leads to a dilemma as exemplified by the following controller: ...

Delaying Variable Assignment in Node.js until Callback Function Completes

I am currently working with Node.js, Express, MongoDB, and Mongoose in my project. One specific task involves fetching the largest id number of a document from the MongoDB database and passing it back to the program. To better organize my code, I moved thi ...

Sorting based on the number of elements in a filtered subdocument array

I have a MongoDB collection structured like this: { { "_id": ObjectId, "user_id": Number, "updates": [ { "_id": ObjectId, "mode": Number, "score": Number } ...

Creating a top-to-bottom pull effect on a single page, similar to the Android title bar, can be achieved using CSS3

Is there a way to achieve an effect in HTML that resembles the pull title bar animation from top to bottom in Android? Any suggestions on how to create this effect or what tools I would need? Currently, when I swipe, the page simply displays a following ...