Juan Vega
Juan Vega

Reputation: 99

Using the new NGRX-Signal Store using withEntities, I'm not able to access the Entity Signal attributes in the TypeScript file

I started using "withEntities" from the new NGRX Signal Store. It works great and is pretty much exactly what I'm looking for.
In my component, I can get it to work and access the "entities" in the template HTML file just fine. However, in the component's typescript file ".ts", I cannot access the data store directly and can't figure out how to do it. Please can someone help?

I have the following code:

Here's the model in src\app\models\builder-expirations.ts

export type BuilderExpirations = {
    id: string;
    CardNumber: number | null;
    DTE: number | null;
    DTE_Min: number | null;
    DTE_Max: number | null;
    Expiration_Name: string | null;
}

Note, in the defined type "BuilderExpirations", I added the "id" field as required in the documentation for using "withEntities" and that is working as expected.

Here's the code that is for the store. src\app\Stores\builder.store.ts

export const BuilderExpirationStore = signalStore(
    { providedIn: 'root' },
    withEntities<BuilderExpirations>(),
    withMethods(
        (store, builderService = inject(BuilderService)) => ({
            async loadAll() {
                const expirations = await builderService.getExpirations();
                patchState(store, addEntities(expirations));
            },
            async insertOrUpdate(id: string, CardNumber: number | null, DTE: number | null, DTE_Min: number | null, DTE_Max: number | null, Expiration_Name: string | null) {
                await builderService.insertOrUpdateExpiration(id, CardNumber, DTE, DTE_Min, DTE_Max, Expiration_Name);
                patchState(store, setEntity({ id: id, CardNumber: CardNumber, DTE: DTE, DTE_Min: DTE_Min, DTE_Max: DTE_Max, Expiration_Name: Expiration_Name }));
            },
            async deleteOne(id: number | null) {
                let idString = id!.toString();
                await builderService.deleteExpiration(idString);
                patchState(store, removeEntity(idString));
            },
            async deleteAll() {
                await builderService.deleteAllExpirations();
                patchState(store, removeAllEntities());
            },
        })
    )
);

Then here's the component in the typescript file src\app\BuilderComponents\expiration-info\expiration-info.component.ts

@Component({
  selector: 'app-expiration-info',
  standalone: true,
  imports: [ExpirationCardComponent, FormsModule, JsonPipe, MatButtonModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule],
  templateUrl: './expiration-info.component.html',
  styleUrl: './expiration-info.component.scss'
})
export class ExpirationInfoComponent implements OnInit {
  
  expirationsList = [0];
  expiryCount = 0;
  builderExpirationStore = inject(BuilderExpirationStore);

  ngOnInit(): void {
    this.loadExpirations()
      .then(() => console.log("Expirations loaded"));
  }

  loadExpirations() {
    // Notice how I am able get the count of records in the data store... this works
    this.expiryCount = this.builderExpirationStore.entities().length;  // <--this works
    if (this.expiryCount === 0) {
      this.expirationsList = [1];
    }
    else {
      let card = 0;
      this.expirationsList = [];
      
      // But then in this for loop, I'm not able to access any 
      // of the attributes from "this.builderExpirationStore.entities()"
      // How can I get this to work?
      for (let exp in this.builderExpirationStore.entities())
      {
        // card = exp.CardNumber;  // this doesn't work... what syntax do I use???
        // card = exp.CardNumber();  // this doesn't work... what syntax do I use???
        // card = exp().CardNumber;  // this doesn't work... what syntax do I use???
        this.expirationsList.push(card);
      }
    }

  }
  
}

So the above code is where I'm having the issue and not able to access the attributes from the NGRX Signal Store using "withEntities" in the component's TypeScript file.

Interestingly, here's the template file or the HTML file where I'm able to get everything to work properly. src\app\BuilderComponents\expiration-info\expiration-info.component.html

<form class="expirations-form" >   
    <div class="exp-card-layout">
        @if (expiryCount === 0) {
            @for (card of expirationsList; track $index) {
                <app-expiration-card class="exp-card-item" [cardNumber]="card"></app-expiration-card>
            }
        }
        @else {
            <!-- Accessing the store data works as expected...nothing wrong here... -->
            @for (card of builderExpirationStore.entities(); track $index) {
                <app-expiration-card class="exp-card-item" [cardNumber]="card.CardNumber">{{ card.CardNumber }}</app-expiration-card>
            }
        }
        
    </div>
    <br>
    <br>
    
    <!-- For testing purposes output the "builderStore.expirations()" store data using JSON... -->
    <!-- Accessing the store data works as expected...nothing wrong here... -->
    <div class="expirations-output">{{ builderExpirationStore.entities().length }}</div>
    <div class="expirations-output">{{ builderExpirationStore.entities() | json}}</div>
</form>

So the above HTML code works as expected and I can access "CardNumber" just fine. But in the typescript file "expiration-info.component.ts", I cannot access "CardNumber". Please can someone advise what syntax I need to use to access "CardNumber" in the NGRX Signal Store using "withEntities"? Thanks in advance.

Upvotes: 0

Views: 1211

Answers (1)

timdeschryver
timdeschryver

Reputation: 15505

The problem occurs within the for loop, this should be:

//            👇 should use `of` instead of `in`
  for (let exp of this.builderExpirationStore.entities())
      {
        // 👇 then you can do 
        card = exp.CardNumber;  // this doesn't work... what syntax do I use???
        // card = exp.CardNumber();  // this doesn't work... what syntax do I use???
        // card = exp().CardNumber;  // this doesn't work... what syntax do I use???
        this.expirationsList.push(card);
      }

Upvotes: 1

Related Questions