Is it necessary to establish a new connection each time I make a request to IndexedDB?

Currently, I am working on a basic Angular project and I have the requirement to save some data in IndexedDB.

In my service, there is an initialization of private db: IDBDatabase; within the constructor: However, I face an issue where this initialized DB is not defined when I try to use it in another method call after the constructor. It seems like the problem might be related to asynchronous calls, callbacks, and promises but I'm having trouble pinpointing the exact cause ... so for now, my temporary workaround is to manually call

window.indexedDB.open("MyTestDatabase", 1);

whenever needed

import {Injectable} from '@angular/core';
import {Directory, Bookmark} from "./models";
import {connectableObservableDescriptor} from "rxjs/internal/observable/ConnectableObservable";

@Injectable({
    providedIn: 'root'
})
export class BookmarksService {

    private db: IDBDatabase;
    private directoriesStoreName = "directories";
    private bookmarksStoreName = "bookmarks";
    
    // Rest of the code remains the same ...

Additionally, here is how I am using a component:

export class DirectoriesListComponent implements OnInit {


    @Input() bookmarks: Bookmark[];
    @Input() directories: Directory[];
    isCollapsed = false;

    common: CommonService;
    bookmarksService: BookmarksService;
    
    // Constructor definition and ngOnInit implementation continues...

Answer №1

There lies an issue in not having control over when the onsuccess function will be executed as it functions as a callback, running at a time beyond your jurisdiction.

However, there are steps you can take to gain control over it. Here's how:

  • Promisify the opening of the database connection and wait for it

Here is an example:

import {Injectable} from '@angular/core';
import {Directory, Bookmark} from "./models";
import {connectableObservableDescriptor} from "rxjs/internal/observable/ConnectableObservable";

@Injectable({
    providedIn: 'root'
})
export class BookmarksService {

  private db: IDBDatabase;
  private directoriesStoreName = "directories"
  private bookmarksStoreName = "bookmarks"
  constructor() {
    console.log("Calling Bookmarks Service Constructor .... ")
    // :refac: you can even call it from the constructor, but won't wait as the constructor can't wait async functions to be completed
    this.initializeDatabase()
  }

  private async getDatabase(): Promise<IDBDatabase> {
    // :refac: Now we create a Promise<IDBDatabase> and wait for it when needed
    return new Promise<IDBDatabase>((resolve, reject) => {
      //
      const openDBRequest: IDBOpenDBRequest = window.indexedDB.open("MyTestDatabase", 1)
      console.log("Let's see if the DB will open .. ")

      /**
      * The only place where a data can be defined is onupgradeneeded callback !
      * @param event
      */
      openDBRequest.onupgradeneeded = (event: any) => {
        console.log("onupgradeneeded fired")
        const db = event.target.result
        resolve(db)
      };

      openDBRequest.onsuccess = (event: any) => {
        console.log("seems that db is opened ! ");
        console.log(event)
        const db = event.target.result
        db.onerror = x => {
          console.log("An error occurred while working with DB! ");
        }
        resolve(db)
      };

      openDBRequest.onerror = event => {
        console.log("can't open IndexedDB");
        console.log(event)
        reject()
      }
    })
  }

  async initializeDatabase(): Promise<void> {
    if (!window.indexedDB) 
      return console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.")
    else if (!this.db)
      this.db = await this.getDatabase()
  }

  async getAllChildDirs(parentId: number): Promise<Directory[]> {
    await this.initializeDatabase()
    if (this.db) {
      const os = this.db.transaction(this.directoriesStoreName).objectStore(this.directoriesStoreName)
      const request = os.index("parent_id")
      const dirs: Directory[] = []
      request.openCursor(IDBKeyRange.only(parentId)).onsuccess = (event: any) => {
        const cursor = event.target.result
        if (cursor) {
          // cursor.key is a name, like "Bill", and cursor.value is the whole object.
          console.log("Name: " + cursor.key + ", SSN: " + cursor.value)
          dirs.push(cursor.value)
          cursor.continue()
        }
      }
      return dirs
    }
  }
}

As you are returning a promise, make sure to use await while calling it:

async ngOnInit(): Promise<void> {
  this.directories = await this.bookmarksService.getAllRootDirs();
  this.bookmarks = await this.bookmarksService.getBookmarks();
  //listens on when button is clicked to collapse the menu !
  this.common.dirsMenuCollapsed.subscribe(val => {
    this.isCollapsed = val
  })
}

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

Issue with VS code/Angular where linter is unable to detect components imported from shared modules

Having an issue with Angular materials components in my project. I have a shared module where I import all the necessary Angular materials modules, and the code runs fine. However, in my html files in VS Code, I see red squiggly lines under every Angular m ...

Expand the space between each pair of rows within a table

After implementing the code below: HTML <table> <tr> <th>Company</th> <th>Contact</th> <th>Country</th> </tr> <tr> <td>Alfreds Futterkiste</td ...

Utilizing React (or Angular) in conjunction with JWT Authentication and managing Sessions/Cookies

My server-side application implements JWT authentication with a React front end (although Angular could also be used for the purposes of this question). Upon initial login, the app exchanges the user's provided username and password for a JWT token t ...

Organize pairs of strings into a nested array within an array using Angular

Currently, I am working on a project in Angular. In this project, I have a string that contains special characters which I have successfully removed using regular expressions. Now, my goal is to arrange the first two strings within square brackets and the ...

What steps should I take to create an object that can be converted into a JSON schema like the one shown here?

I'm facing a rather simple issue, but I believe there's something crucial that I'm overlooking. My objective is to iterate through and add elements to an object in order to generate a JSON structure similar to the following: { "user1": ...

Encountered an issue when attempting to access a user's full details page in Angular 14

An error occurred in main.ts at line 6: TypeError - Cannot read properties of undefined (reading 'id'). The issue is located in the ContactUserDetailsComponent_Template in contact-user-details.component.html at line 17. This error is being hand ...

Discovering the ins and outs of utilizing Validator.pattern in Angular 9

BGroup = new FormGroup({ test: new FormControl(null, [Validators.required, Validators.pattern("[0-9]*$")]) }); Greetings! I am currently using Angular 9 and I have a question. How can I define a pattern that only accepts decimal numbers? Speci ...

Issue with ChartistJS Angular2: Chart appears only when window is resized

Hey There, I've been working on incorporating ChartistJS to render a chart. One strange thing I noticed is that when I resize the window, the chart data suddenly appears. This makes me think that I might be rendering the chart with incomplete data. ...

What is the best way to sort a list with parent and child elements using Angular 2?

I have a tree structure in Angular 1 that allows me to filter the list at any level by typing in a textbox. Check out this demonstration to see it in action. Now, I am working on converting this functionality to Angular 2 and aiming for the desired output ...

"Exploring the Concept of Tuple Narrowing and Type

Is there anyone who can assist me in comprehending the scenario below: export function functionThatReturnsTurpleObjects(): | [{ a: number }, undefined] | [undefined, { a: number }] { if (Math.random() > 0.5) { return [undefined, { a: 1 }]; ...

The input type '{}' does not match the expected type 'Readonly<IIdeasContainerProps>'. The property '...' is not found in the type '{}'

Having recently started using TypeScript, I'm encountering some issues when attempting to execute this code snippet. Error The error message reads as follows: Failed to compile 13,8): Type '{}' is not assignable to type 'Readonly &l ...

Is it true that "Conditional types" are not compatible with actual functions?

Checking out https://www.typescriptlang.org/docs/handbook/2/conditional-types.html I'm curious as to why this code is not functioning properly? interface IdLabel { id: number } interface NameLabel { name: string } type NameOrId<T extends num ...

Angular - Automatically hide sidebar menu upon selecting a menu item

Struggling to hide a sidebar menu after clicking on a menu item that you created? I ran into the same issue and tried following the example from a tutorial on Do I really need to call toggleMenu on (click) of every hyperlink in the HTML? If so, how do I i ...

Steps to resolve Angular NX project NG0203 issue

Facing the challenge of dealing with the NG0203 error, all while my colleagues are effortlessly working on the project without any issues. Despite attempting to update and revert back the versions of Angular and Nx, the problem persists. I even went as far ...

What is the best way to distribute items into an array?

What is the correct way to push objects into an array similar to how the spread operator works for non-objects? I am looking for a solution like this: state.selected = [state.selected, ...action.payload] // Type 'object' is not an array type. I ...

Firestore TimeStamp.fromDate is not based on UTC timing

Does anyone have a solution for persisting UTC Timestamps in Firestore? In my Angular application, when I convert today's date to a Timestamp using the code below, it stores as UTC+2 (due to summer time in Switzerland). import {firebase} from ' ...

Encountering difficulty importing TypeScript files dynamically within a Deno executable

When attempting to import a file from aws in an exe using its public link based on user input, I am facing difficulties For example, I generated my exe with the command below deno compile --allow-all main.ts Users execute this exe using commands like ./e ...

Creating an object key using a passed literal argument in TypeScript

Can the following scenario be achieved? Given an argument, how can we identify the object key and access it? Any potential solutions? async function checkKey(arg:'key1'|'key2'){ // fetchResult returns an object with either {key1:&apo ...

Is it possible to bind the Polymer paper-dropdown-menu with ngControl in Angular?

I'm currently working on building a form in Angular2 using the Polymer paper-dropdown-menu element. I've been struggling to figure out how to bind the selected value of the dropdown to my component's control. Despite numerous attempts, I hav ...

Obtaining API/JSON Data to Implement in a NextJS Application

Currently, I am working on developing a NextJs website that focuses on detecting crop diseases. The process involves sending photos and environmental data to a fastapi python server for processing. Subsequently, the processed data is supposed to be display ...