Home > Blockchain >  Angular/TypeScript treats array as object and throws an Error: Cannot find a differ supporting objec
Angular/TypeScript treats array as object and throws an Error: Cannot find a differ supporting objec

Time:02-11

My code is the following in my component, I defined this:

public outputFormats =  ["pdf", "png32", "png8", "jpg", "gif", "eps", "svg"];

In my template:

  <div ngbDropdownMenu aria-labelledby="polylineStyleDropdown">
     <button  *ngFor="let format of outputFormats"
         (click)="onOutputFormatChanged(format)">{{format}}
     </button>
  </div>

But I get the following error on init.

  ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
      at NgForOf.ngDoCheck (common.js:3323:1)
      at callHook (core.js:2536:1)
      at callHooks (core.js:2495:1)
      at executeInitAndCheckHooks (core.js:2446:1)
      at selectIndexInternal (core.js:8447:1)
      at Module.ɵɵadvance (core.js:8430:1)
      at PrintComponent_Template (print.component.html:41:48)
      at executeTemplate (core.js:9598:1)
      at refreshView (core.js:9464:1)
      at refreshComponent (core.js:10635:1)
  defaultErrorLogger @ core.js:6479
  handleError @ core.js:6527
  (anonymous) @ core.js:29723
  invoke @ zone.js:372
  run @ zone.js:134
  runOutsideAngular @ core.js:28604
  tick @ core.js:29723
  (anonymous) @ core.js:29571
  invoke @ zone.js:372
  onInvoke @ core.js:28705
  invoke @ zone.js:371
  run @ zone.js:134
  run @ core.js:28559
  next @ core.js:29570
  __tryOrUnsub @ Subscriber.js:183
  next @ Subscriber.js:122
  _next @ Subscriber.js:72
  next @ Subscriber.js:49
  next @ Subject.js:39
  emit @ core.js:25968
  checkStable @ core.js:28627
  onLeave @ core.js:28755
  onInvokeTask @ core.js:28699
  invokeTask @ zone.js:405
  runTask @ zone.js:178
  invokeTask @ zone.js:487
  invokeTask @ zone.js:1600
  globalZoneAwareCallback @ zone.js:1626

When I did console.log(typeof this.outputFormats), it returns object. I tried to convert it to array using Array.from(this.outputFormats), Object.values(this.outputFormats) but the result is still the same, it is output is still an object.

Versions: Angular Cli 12.1.4 TypeScript 4.3.5

Solutions that didn't work for me:

https://github.com/angular/angular/issues/6392

Angular error : Cannot find a differ supporting object '[object Object]'

Angular: Cannot find a differ supporting object '[object Object]'

CodePudding user response:

I've got modified a version of the documentation example to use what you've shared and it's working at https://stackblitz.com/edit/angular-3pnr1l with the TS/Angular versions you specified. It's ng-bootstrap 11.0 for what it's worth, but you hadn't specified that.

One difference in the implementation is the use of <Button ngbDropdownItem.

# dropdown-basic.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

import { NgbdDropdownBasic } from './dropdown-basic';

@NgModule({
  imports: [BrowserModule, NgbModule],
  declarations: [NgbdDropdownBasic],
  exports: [NgbdDropdownBasic],
  bootstrap: [NgbdDropdownBasic]
})
export class NgbdDropdownBasicModule {}

# dropdown-basic.ts
import {Component} from '@angular/core';

@Component({
  selector: 'ngbd-dropdown-basic',
  templateUrl: './dropdown-basic.html'
})
export class NgbdDropdownBasic {
  public outputFormats =  ["pdf", "png32", "png8", "jpg", "gif", "eps", "svg"];
}

# dropdown-basic.html
<div ngbDropdown >
  <button  id="dropdownBasic1" ngbDropdownToggle>
    Toggle dropdown
  </button>
  <div ngbDropdownMenu aria-labelledby="polylineStyleDropdown">
    <button
      ngbDropdownItem
      
      *ngFor="let format of outputFormats"
    >
      {{format}}
    </button>
  </div>
</div>

If it's not working for you with this exact setup, then this error may be a red herring and you could have your hands full with isolating exactly what's causing it to break. We don't have enough insight into your surrounding code to really diagnose this. Hopefully you spot something that's obvious and different from this example.

CodePudding user response:

The issue was not related to the code that was in the question. I made a mistake in assigning enum to a property called printModes then I used that property in another ngFor in the template. Error:

enum PrintModes {
  CurrentView = 'Current View',
  AdjustableBox = 'Adjustable Box',
  DrawnBoundary = 'Drawn Boundary'
}

Then inside the component:

public printModes = PrintModes

In the template:

     <div ngbDropdown >
        <button  ngbDropdownToggle>
          {{printMode}}
        </button>
        <div ngbDropdownMenu aria-labelledby="polylineStyleDropdown">
          <button  *ngFor="let area of printModes"
                  (click)="onPrintAreaChanged(area)">{{area}}
          </button>
        </div>
      </div>

The error in the forked stackblitz is correct and relevant to the mistake but in my app, it does not show the original error. Somehow, the original error made typescript misbehave.

Stackblitz error:

Error in src/app/dropdown-basic.html (7:54)
Type 'typeof PrintModes' is not assignable to type 'NgIterable<any>'.
Type 'typeof PrintModes' is not assignable to type 'Iterable<any>'.

To fix the issue, inside the component I just need to change

public printModes = PrintModes;

To

public printModes = Object.values(PrintModes);
  • Related