Angular 2. How to set initial state from Asp.net MVC View - asp.net-mvc

How can I set initial state of Angular 2 app from view?
I have a controller that must pass initial state throw the view to angular 2 component.

Currently you can't pass data to the root level component via a property, but you can however define a global variable outside the component and refer to it in your component. This might not be ideal, but perhaps not too bad either.
jquery is an example of this. In the below example the global jquery variable is referenced from my component. You could do the same with your own global variable. You could use server side rendering to dynamically create your global variable when the page renders.
import {Component, ElementRef, Inject, OnInit} from 'angular2/core';
declare var jQuery:any;
#Component({
selector: 'jquery-integration',
templateUrl: './components/jquery-integration/jquery-integration.html'
})
export class JqueryIntegration implements OnInit {
elementRef: ElementRef;
constructor(#Inject(ElementRef) elementRef: ElementRef) {
this.elementRef = elementRef;
}
ngOnInit() {
jQuery(this.elementRef.nativeElement).find('.moving-box').draggable({containment:'#draggable-parent'});
}
}

Why don't you hydrate the initial state of the application by calling a WebApi endpoint in ngOnInit()? That way your application is relying on a standard HTTP response rather than a piece of MVC infrastructure...

Related

How do you create a singleton component in Dart and pass a handler to it to all other components when needed?

I'm trying to create a central notification service for the app, to report simple errors via the same "pipeline". It may be the wrong approach, but I need a material-popup stuck to the main HTML body, displaying on-demand as required by various components.
import 'package:angular/angular.dart';
import 'package:angular_components/angular_components.dart';
import 'package:angular_components/laminate/overlay/zindexer.dart';
#Component(
selector: 'hv-alerts',
templateUrl: 'alert_service.html',
directives: [
MaterialPopupComponent,
PopupSourceDirective
],
providers: [
ClassProvider(ZIndexer),
materialProviders,
popupBindings
]
)
class AlertService {
RelativePosition get popupPosition => RelativePosition.AdjacentTop;
bool popupVisible = false;
void setVisible(bool flag) {
popupVisible = flag;
}
PopupSizeProvider popupSize = FixedPopupSizeProvider(
minWidth: 400,
minHeight: 75,
maxWidth: 600,
maxHeight: 75
);
static final AlertService _instance = AlertService();
}
Is there a way to pass in the handler to this material-popup via a singleton or Factory or whatever, and allow other services to call an AlertService.show()?
This is what I would do:
Create an Alert Service (not a component, a regular class)
Inject this alert service into your AppComponent
Use this service to pass around the view that controls the popup and manipulate it accordingly
It is quite easy to pull-off.
The component's lifecycle is dependant on the element in the templates itself. Such if you had two elements with the same selector you would have two components. You can't have them by singletons themselves.
That said how I would do this is abstract the service part of it, and have it be a separate class that would be injected into the popup component and any usage. The popup would listen to a stream know when to show the popup, and the clients would send an event on a StreamController to tell the popup when to show. If you wanted to be a bit safer you could provide two different interfaces the stream, and the stream controller which were backed by the same entity. This would allow you more quickly see who was consuming alerts, and who was producing them.

Multiple instances of one service

I have a simple service
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class CompToCompService {
private data = new Subject<any>();
data$ = this.data.asObservable();
constructor() { }
Send(value: any) {
this.data.next(value);
}
}
I use it to sling some light data back and forth between components.
I have however found myself needed to use it twice in the same component to send data and use different components to listen. As angular services are now by default singletons everything is being jumbled together.
Is it possible to create different instance of the server and if so how do I get the listening components to listen to the right instance?
If not what's the best way to accomplish what I am trying to do. I am trying to avoid creating a tiny service like that for every piece of communication I need to do. I know of events but my communications are across the routing-outlet and events don't seem to like that.
Create a parent component with two or more child components.
in each child component use
providers: [serviceName]
Then you will have tow instance of service .
but you must work with each instance in their component

Angular2 Dart: Dividing a project in packages does not allow to reuse base components with modified providers

I have a big application using Dart (1.24.2) and angular dart (3.1.0).
I decided to split the application into two packages: the first is a foundation layer and the second is the true application package. The idea is to be able to reuse the foundation layer in other projects.
In the foundation layer I use several services (providers) that are global to the application and are widely used.
Now, in the application layer I had the need to add some fields to some services.
The problem I had is that you cannot use a component of the foundation layer that uses a service modified. The message that I get is: "EXCEPTION: No provider found for ."
I cannot say that this is bug, but It would be helpful in creating angular modules.
An example.
I have generated (from Webstorm) an example application using Angular2: The Todo list application.
Given this, I Have modified a little bit the "src/todo_list/todo_list_component.dart" source removing the TodoListService provider.
//providers: const [TodoListService],
and moving the declaration into the AppComponent class:
import 'src/todo_list/todo_list_service.dart';
// AngularDart info: https://webdev.dartlang.org/angular
// Components info: https://webdev.dartlang.org/components
#Component(
selector: 'my-app',
styleUrls: const ['app_component.css'],
templateUrl: 'app_component.html',
directives: const [materialDirectives, TodoListComponent],
providers: const [materialProviders, TodoListService],
)
class AppComponent {
This way the service is global to all components call by AppComponent.
Then I have generated a second project, always a TodoList example and made the same modifications as in the previous (globalizing the TodoListService).
Now, in the derived package I did the following:
Added a reference to the foundation layer package;
Cancelled the src/todo_list/todo_list_component.dart, .css and .html.
This because I want to use the foundation layer package TodoList component.
Added a field to the TodoListService:
import 'package:angular2/core.dart';
import 'package:angular_inject_subclass_base/src/todo_list/todo_list_service.dart' as base;
/// Mock service emulating access to a to-do list stored on a server.
#Injectable()
class TodoListService extends base.TodoListService {
String description;
}
Last modification, in the AppComponent source, I changed the reference to the TodoListComponent of the foundation layer:
import 'package:angular_inject_subclass_base/src/todo_list/todo_list_component.dart';
Trying to run the derived project I got the following error:
(anonymous function) EXCEPTION: No provider found for TodoListService. STACKTRACE:
0 _EmptyInjector.get (package:angular2/src/core/di/injector.dart:54:7)
1 _MapInjector.get (package:angular2/src/core/di/injector.dart:73:52) 2 ReflectiveInjectorImpl._getByKeyDefault (package:angular2/src/core/di/reflective_injector.dart:816:18)
3 ReflectiveInjectorImpl._getByKey (package:angular2/src/core/di/reflective_injector.dart:782:14)
4 ReflectiveInjectorImpl.get (package:angular2/src/core/di/reflective_injector.dart:529:17)
5 AppView.injectorGet (package:angular2/src/core/linker/app_view.dart:236:37)
6 DebugAppView.injectorGet (package:angular2/src/debug/debug_app_view.dart:98:31)
7 ViewAppComponent0.build (package:angular_inject_subclass_derived/app_component.template.dart:90:71)
8 AppView.create (package:angular2/src/core/linker/app_view.dart:180:12)
Is there any other way of doing this?
Is it possible to change this behavior in Angular so that also a subclass of the provider can be injected instead of the original one?
You can provide subclasses using
providers: const [
materialProviders,
const Provider(base.TodoListService, useClass: TodoListService)
],
then when some class depends on base.TodoListService, Angular will inject the subclass TodoListService which will be compatible with the called constructor because it is a subclass.
TodoListService alone is a short form (that will probably discontinued in Angular 5) for const Provider(TodoListService, useClass: TodoListService)

Angular2 Inject components into other components

I'm messing around with Angular2 and I'm wanting the ability to inject one component into another based on the bootstrapped bindings.
class HelloComponent {
name: string;
}
#Component({
selector: 'hello'
}
#View({
template: `<h3>Hello {{ name }}</h3>`
})
class HelloBobComponent extends HelloComponent {
constructor() {
this.name = 'Bob';
}
}
#Component({
selector: 'app'
}
#View({
directives: [HelloComponent]
template: `<h1>Welcome to my Angular2 app</h1>
<hello></hello>`
}
class AppComponent {
}
bootstrap(AppComponent, [
bind(HelloComponent).toClass(HelloBobComponent)
]);
Here I'm using HelloComponent as a token that I want Angular2's Injector to resolve HelloBobComponent. I'm doing this so that I can swap components in and out based on the current app configuration. The above example obviously doesn't work. Is this possible using one of the frameworks decorators? I haven't found an answer yet digging though blogs or the source.
edit: To clarify, how do I get the directives property on the View decorator to treat HelloComponent as a di token instead of a type.
This is currently not supported as of alpha37. The compiler resolves directives passed in the View decorator by either type or binding but does not look up from the parent injector.
For example:
#View({
url: '...',
directives: [
Directive1,
bind(Directive2).toClass(Directive2Impl),
]
})
The intention for the "directives" property here was only to prevent selector naming collision. Later bind support was added to aid in testing.
The only solution I can think of without editing the compiler function would be to maintain an external Injector and resolve types on component declaration.

Is it possible to declaratively bind a CustomEvent handler when using Dart Web UI WebComponents?

I've tried to bind a custom event handler to a WebComponent that has an EventStreamProvider exposed via a getter, but it comes back with "Class 'DivElement' has no instance getter 'onMainAction'.".
Trimmed down component .dart code...
import 'dart:html';
import 'dart:async';
import 'package:web_ui/web_ui.dart';
class SegmentedButtonsListComponent extends WebComponent {
static const EventStreamProvider<CustomEvent> mainActionEvent = const EventStreamProvider<CustomEvent>("MainActionEvent");
Stream<CustomEvent> get onMainAction => mainActionEvent.forTarget(this);
}
Trimmed usage of component…
<x-segmented-buttons-list id="segmented-buttons-list" on-main-action="eventHandler($event)"></x-segmented-buttons-list>
Trimmed code from main.dart…
import 'dart:html';
import 'dart:async';
import 'package:web_ui/web_ui.dart';
const EventStreamProvider<CustomEvent> mainActionEvent = const EventStreamProvider<CustomEvent>("MainActionEvent");
void eventHandler(CustomEvent event) {
print("""
Yabba Dabba Doo!
Type: ${event.type}
Detail: ${event.detail}
""");
}
void main() {
mainActionEvent.forTarget(query('#segmented-buttons-list')).listen(eventHandler);
}
The "MainActionEvent" custom events are being dispatched by components instantiated within this "list" component.
As you can see from the above example I can catch the events if I create an EventStreamProvider in main.dart and target the component, that works fine (but by-passes the Stream getter in the component).
It would be great though if I could dispense with the EventStreamProvider in main.dart and simply bind to the onMainEvent getter on the component.
Is that possible?
Update 2013-05-05:
Siggi explains below that at present it is not possible to do this, but there is a way to reference the component's CustomEventProvider's getter via the element's xtag.
I found that I had to use a Timer to query the DOM after main() has completed because xtags aren't populated until the main() event loop has finished.
void postMainSetup() {
query('#segmented-buttons-list').xtag.onMainAction.listen(eventHandler);
}
void main() {
Timer.run(postMainSetup);
}
With the above setup a new CustomEventProvider isn't needed to monitor the component.
Good question!
I see a couple parts to this question:
using custom events directly on a component: Currently web_ui uses different objects to represent your component and the actual dom element it represents. In the future, we plan to extend directly from "DivElement" instead of "WebComponent" and that will allow you to do what you wrote.
Meanwhile, you'll have to be more explicit when you want to use the host or shadow root of your component. In your example, it seems like you want to attach the event to the host, so you would need to write something more like this:
Stream<CustomEvent> get onMainAction => mainActionEvent.forTarget(this.host);
using 'on-someting-foo' syntax in a component: you probably found a bug/missing feature =). Currently we treat attributes in a special way and bind their values to fields of a component if we identify that the target was corresponds to a component. We do this for value bindings, but not yet for binding custom events. A workaround before this feature is added, would be to query for your element and attach the event by hand:
query('#host-node').xtag.onMainAction.listen(...);

Resources