Skip to content

Latest commit

 

History

History
247 lines (169 loc) · 6.47 KB

step-3.md

File metadata and controls

247 lines (169 loc) · 6.47 KB

Step 3: Add a button and controller

In this step you add a button and a controller that coordinates the button, label, and badge. You also start splitting your code into multiple libraries. Implementing multiple libraries is optional, but it's a good way to modularize your app.

Keywords: controller, module, click event, defining a library

Create a lib directory and new Dart files

→ Create a lib directory at the same level as the web directory.

You can do this at the command line, in a Finder, or in Dart Editor. In Dart Editor, right-click the top directory (s1_basics), choose New Folder..., and specify the name lib.

→ Under lib, create a file named badge_controller.dart.

To do this in Dart Editor, right-click the lib directory, choose New File..., and specify the name badge_controller.dart.

→ Under lib, create a file named pirate_module.dart.

Key information:

  • The pub package layout conventions specify the lib name and location.
  • The pub package manager looks under lib for any libraries that are imported with package:this_package (where this_package is the current package's name, as declared in the pubspec).
  • Both badge_controller.dart and pirate_module.dart will declare libraries.

Implement the controller

To implement the controller for this app, edit lib/badge_controller.dart.

→ Add the following code to declare and import libraries.

library s1_basics.badge_controller;

import 'package:angular/angular.dart';

If you're using Dart Editor, it warns you that the import is unused.

→ Create an empty class named BadgeController, and give it a name property.

...
class BadgeController {
  String name = '';
}

→ Add an NgController annotation to the class.

@NgController(
  selector: '[badge-controller]',
  publishAs: 'ctrl')
class BadgeController {   

Key information:

  • The NgController annotation tells Angular that BadgeController is an Angular controller.
  • The required selector argument defines the CSS selector that triggers the controller. It can be any valid CSS selector that does not cross element boundaries.
  • The publishAs argument specifies that the controller instance should be assigned to the current scope under the specified name.

→ Define some constant strings for the UI.

Class BadgeController {
  static const DEFAULT_NAME = 'Anne Bonney';
  static const LABEL1 = 'Arrr! Write yer name!';
  static const LABEL2 = 'Aye! Gimme a name!';
  String name = '';
  ...

Note that Dart Editor italicizes static values (and static methods, too).

→ Add an inputIsNotEmpty getter, a label getter, and a generateName() method to BadgeController.

  String name = '';
  
  bool get inputIsNotEmpty => name.trim().isNotEmpty;
  String get label => inputIsNotEmpty ? LABEL1 : LABEL2;

  generateName() {
    name = DEFAULT_NAME;
  }
}

Register the controller

To register the BadgeController class, you need to edit lib/pirate_module.dart.

→ Add the following code to declare and import libraries.

library s1_basics.pirate_module;

import 'package:angular/angular.dart';
import 'package:s1_basics/badge_controller.dart'; 

→ Add a subclass of Angular's Module class, and register BadgeController.

...
class PirateModule extends Module {
  PirateModule() {
    type(BadgeController);
  }
}

Key information:

  • The Module class provides all of Angular’s built-in services and directives.
  • The code type(BadgeController) adds BadgeController to the list of modules that Angular loads.

Instantiate and use the module

Now edit main.dart, so that it uses a PirateModule object.

→ Modify the main() method to instantiate PirateModule.

import 'package:s1_basics/pirate_module.dart';

void main() {
  ngBootstrap(module: new PirateModule());
}

Hook up the controller to the HTML file

Now edit web/index.html, so that it uses the controller.

→ Add badge-controller to the <body> element.

<body badge-controller>

Key information:

  • Thanks to the badge-controller selector, a BadgeController now controls every element under <body>.

→ Move ng-cloak up to the <body> element.

<body badge-controller ng-cloak>
...
<span id="badgeName">{{name}}</span>

→ Add a button element under the input field.

<div class="widgets">
  <div>
    <input type="text" id="inputName" maxlength="15" ng-model="name">
  </div>
  <div>
    <button ng-click="ctrl.generateName()">{{ctrl.label}}</button>
  </div>
</div>

Key information:

  • ng-click is a built-in Angular directive that allows you to specify custom behavior when an element is clicked. In our example, it invokes the generateName() method on the controller.
  • As {{ctrl.label}} shows, an Angular expression can refer to a getter.

→ Update data binding: replace name with ctrl.name.

<input type="text" id="inputName" maxlength="15" ng-model="ctrl.name">
...
<span id="badgeName">{{ctrl.name}}

→ Add a ng-disabled directive to the button tag.

<button ng-click="ctrl.generateName()"
    ng-disabled="ctrl.inputIsNotEmpty">{{ctrl.label}}</button>

Key information:

  • ng-disabled disables the element whenever the condition is true. In this case, the button is disabled whenever the input field contains text.

  • Like ng-click, ng-disabled is a built-in AngularDart directive.

Run the app in Dartium

→ Once the app is running, click the button.

"Anne Bonney" appears in the text field and badge, and the button becomes disabled.

→ Erase all text from the input field.

The button becomes enabled again.

Problems?

Check your code against the files in s3_controller.

Don't worry about differences in package names. Your files should contain the string s1_basics wherever the files in s3_controller contain s3_controller.