【问题标题】:How to access angular.dart component´s attribute or method如何访问 angular.dart 组件的属性或方法
【发布时间】:2014-01-16 01:05:45
【问题描述】:

我这样定义了一个 angular.dart 组件

@NgComponent(
    selector: 'dartcomp',
    templateUrl: 'dartComp.html',
    publishAs: 'ctrl',
    map: const
    { 
      'val' : '@val'
    }
)
class DartComp
{ 
  String val;
  calc(a,b) =>a+b;
}

在 HTML 中的用法是:

 <dartcomp id="dc"></dartcomp> 

如何从主 dart 访问 angular.dart 组件的属性 val 或方法 calc()

对组件的调用类似

querySelector("#dc").val = "Frank";

投掷:

“UnknownElement”类没有实例设置器“val=”。

NoSuchMethodError : method not found: 'val='
Receiver: Instance of 'UnknownElement'
Arguments: ["Frank"]

错在哪里?

【问题讨论】:

  • 扩展了我的回答,提出了在 Angular 组件/指令上调用方法的建议解决方案
  • 我扩展了 index.dart 来演示如何传递数据和回调。

标签: dart angular-dart


【解决方案1】:

访问类属性等属性在 Polymer 中有效,但在 Angular.Dart 中无效。 你必须使用 Elements 默认方法.attributes['attrName'] = value

// this doesn't work with Angular
//    querySelector("#dc").attributes['val'] = "Frank";

// I found an AngularDart function that may help but it's comment says this is for debugging only
// this example calls the method 'add' on MyComponent
  var mc = ngProbe(dom.querySelector('my-component')).directives.firstWhere((d) => d is MyComponent);
  mc.add('someValue');

也许有更好的方法我不知道,但无论如何这种方法应该可以工作。

在 Angular 组件/控制器上调用方法的解决方法

这里也有示例: GitHub BWU-Dart Playground

这是我想出的最好的主意。 也许 AngularDart 的创建者中有人知道更好的解决方案。 (我也找不到 AngularJS 的直接解决方案)

EventBus

/**
 * Derived from https://github.com/marcojakob/dart-event-bus
 */

library eventbus;

import "dart:async";
import "dart:html";

import "package:logging/logging.dart";

/**
 * [EventBus] is a central event hub.
 * In addition it automatically updates the page navigation history ([History]
 * by calling [window.pushState] for fired events which indicate, that they
 * are supposed to update the [History] and refiring events which led to
 * [window.pushState] in the case of a [window.onPopState] event.
 */
class EventBus extends Object {
  final _logger = new Logger("EventBusModel");

  /**
   * A [StreamController] is maintained for each event type.
   */
  Map<EventType, StreamController> streamControllers = new Map<EventType, StreamController>();

  bool isSync = true;

  /**
   * Constructs an [EventBus] and allows to specify if the events should be
   * send synchroniously or asynchroniously by setting [isSync].
   */
  EventBus({this.isSync : false});

  /**
   * [on] allows to access an stream for the specified [eventType].
   */
  Stream/*<T>*/ on(EventType/*<T>*/ eventType) {
    _logger.finest('on');

    return streamControllers.putIfAbsent(eventType, () {
      return new StreamController.broadcast(sync: isSync);
      }
    ).stream;
  }

  /**
   * [fire] broadcasts an event of a type [eventType] to all subscribers.
   */
  void fire(EventType/*<T>*/ eventType, /*<T>*/ data) {
    _logger.finest('event fired: ${eventType.name}');

    if (data != null && !eventType.isTypeT(data)) {
      throw new ArgumentError('Provided data is not of same type as T of EventType.');
    }

    var controller = streamControllers[eventType];
    if (controller != null) {
      controller.add(data);
    }
  }
}

/**
 * Type class used to publish events with an [EventBus].
 * [T] is the type of data that is provided when an event is fired.
 */
class EventType<T> {

  String name;

  /**
   * Constructor with an optional [name] for logging purposes.
   */
  EventType(this.name);

  /**
   * Returns true if the provided data is of type [T].
   *
   * This method is needed to provide type safety to the [EventBus] as long as
   * Dart does not support generic types for methods.
   */
  bool isTypeT(data) => data is T;
}

index.dartMyComponentma​​in()

library main;

import 'dart:html' as dom;
import 'dart:async';
import 'package:angular/angular.dart';
import 'package:di/di.dart';

import 'event_bus.dart';

class Item {
  String name;
  Item(this.name);
}

@NgComponent(
    selector: 'my-component',
    publishAs: 'ctrl',
    applyAuthorStyles: true,
    template: '''<div ng-repeat="value in ctrl.values"><span>{{value.name}}</span> - <content><content></div>'''
)

class MyComponent {
  List<Item> values = [new Item('1'), new Item('2'), new Item('3'), new Item('4')];

  void add(String value) {
    values.add(new Item(value));
  }

  EventBus _eb;

  MyComponent(this._eb) {
    print('MyComponent');
    _eb.on(Events.someEvent).listen((e) => add(e));
    _eb.on(Events.someEventWithData).listen((SomeEventData ed) {
      print('Event received from ${ed.senderId}');
      ed.respond(this);
    });
  }
}


typedef MyComponentEventResponse (MyComponent component);
class SomeEventData {
  SomeEventData(this.respond, this.someOtherData, [this.senderId]);
  MyComponentEventResponse respond;
  var someOtherData;
  String senderId;
}

class Events {
  static final EventType<String> someEvent = new EventType<String>("someEvent");
  static final EventType<SomeEventData> someEventWithData = new EventType<SomeEventData>("someEventWithData");
}

class MyAppModule extends Module {
  MyAppModule() {
    type(MyComponent);
    value(EventBus, new EventBus());
  }
}

void main() {
  Injector inj = ngBootstrap(module: new MyAppModule());

  EventBus eb = inj.get(EventBus);

  eb.fire(Events.someEvent, "17");
  new Timer(new Duration(milliseconds: 1000), () => eb.fire(Events.someEvent, "33"));
  new Timer(new Duration(milliseconds: 2000), () => eb.fire(Events.someEventWithData, new SomeEventData(respond, 'blabla', 'main105')));
}

void respond(MyComponent c) {
  dom.window.alert('Demonstrate access to event receiver: Name of 2nd item: ${c.values[1].name}');
}

index.html

<!DOCTYPE html>

<html ng-app>
  <head>
    <meta charset="utf-8">
  </head>

  <body>

    <h3>Repeat</h3>
    <my-component>
      <div>some provided content to repeat</div>
    </my-component>

    <script type="application/dart" src="index.dart"></script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

【讨论】:

  • 当然可以。我的答案中的那一行是问题中的那一行,其中包含应用了更正的错误。我是用手机写的,所以有点短。我会延长一点。
  • 不知何故,这个答案被标记为低质量。我确定@tepkenvannkorn 没有很好地研究答案。寿,也许扩展一点会有所帮助。 :)
  • Tnx!我也可以从主 dart 程序中调用组件的方法吗?
  • 我也想知道这一点,但还没有时间看看它是如何工作的。当我找到解决方案时,我会尝试并扩展答案。
  • Tnx!通过 .attributes['attrname'] 访问的属性也可以是对象吗?
【解决方案2】:

我尝试了不同的方法。

在组件的静态映射中,我存储了组件的实例,以便稍后可以在 main.dart 中访问该组件

@NgComponent(
    selector: 'dartcomp',
    templateUrl: 'dartComp.html',
    publishAs: 'ctrl',
    map: const
    { 'val' : '@val',
      'id'  : '@id'
    }

)
class DartComp implements NgAttachAware
{ static Map<String,DartComp> comp = new Map();

  String id;
  String val;

  void attach()
  { comp[id]=this; }
}

组件 html:

<span> Component val:{{ctrl.val}}:   </span>

在 index.html 中我放了 2 个组件

<dartcomp id="dc1"></dartcomp>
<dartcomp id="dc2" val="max"></dartcomp>

在 main.dart 中我尝试更改组件 dc1 的 val 属性

DartComp.comp['dc1'].val="frank";

但在浏览器中我看不到变化。 有没有办法解决这样的问题?

【讨论】:

  • 我也想过这个,但是你必须小心不要造成内存泄漏。分配给此地图的元素不能被垃圾回收。即使它们从 DOM 中移除,它们也会留在内存中。
猜你喜欢
  • 2020-10-18
  • 1970-01-01
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
  • 2013-11-23
  • 1970-01-01
  • 2018-07-20
  • 1970-01-01
相关资源
最近更新 更多