Custom Element – null reference from query() in constructor

Issue

I’m working on my first Dart app, having completed the Game of Darts tutorials. I am trying to create a semantically named top-menu element that will eventually display a list of navigation menu tabs at the top of my page. My Dart app is able to recognize my custom element and calls the associated constructor.

However, I am getting a null reference when trying to query for the UL element within my custom element. I need the UL reference in order to dynamically load my LI elements into the menu.

Question 1:
Should the element be visible in the DOM at the point where the constructor is running?

Question 2:
If it is not yet visible, is there a Dart event I can use to trigger loading of the LI elements after the custom element has been completely loaded into the DOM?

Thanks in advance! For reference, here is the source of my custom element:

topmenu-element.html

<!DOCTYPE html>

<html>
  <body>
    <element name="top-menu" constructor="TopMenu" extends="div">
      <template>
        <div>
          Top Menu
          <ul id="top-menu-list"></ul>
        </div>
      </template>
      <script type="application/dart" src="topmenu-element.dart"></script>
    </element>
  </body>
</html>

topmenu-element.dart

import 'package:web_ui/web_ui.dart';
import 'dart:html';

class TopMenu extends WebComponent {

  List menuItems = ['Session', 'Authentication Services', 'Vehicle Services', 'Subscriber Services', 'Data Services'];

  void populateMenu() {
    UListElement menuList = query('#top-menu-list');
    LIElement newMenuItem = new LIElement();
    newMenuItem.text = menuItems[0];
    menuList.children.add(newMenuItem);
  }

  TopMenu() {
    // populateMenu();
  }

}

Solution

I can’t speak specifically about the DOM visibility in a constructor with the query method as I’m truthfully not certain. However there are perhaps better methods which you can use, which are called at various stages in the elements lifecycle.

That said, can I ask why you need to use this particular method to add the children. It is probably much easier to do it with the template repeat like so:

<!DOCTYPE html>

<html>
  <body>
    <element name="top-menu" constructor="TopMenu" extends="div">
      <template>
        <div>
          Top Menu
          <ul id="top-menu-list">
            <li template repeat="item in menuItems">{{item}}</li>
          </ul>
        </div>
      </template>
      <script type="application/dart" src="topmenu-element.dart"></script>
    </element>
  </body>
</html>

Then there’s no need to put any of your menu display code in your constructor.

Answered By – Matt B

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *