<!DOCTYPE html>
<html>
<head>
<base href="." />
<title>angular 5 test env</title>
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" />
<link href="https://unpkg.com/@angular/material/prebuilt-themes/deeppurple-amber.css" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="./app/style.css" />
<script src="https://unpkg.com/zone.js@0.8.12/dist/zone.js"></script>
<script src="https://unpkg.com/zone.js@0.8.12/dist/long-stack-trace-zone.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
<script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
<script src="//cdn.jsdelivr.net/underscorejs/1.5.2/underscore-min.js"></script>
<script data-require="moment.js@2.10.2" data-semver="2.10.2" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.2/moment.min.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function (err) { console.error(err); });
</script>
</head>
<body>
<my-app></my-app>
</body>
</html>
//our root app component
import { Component, NgModule, OnInit, ViewContainerRef, OnDestroy, ViewChild, ElementRef } from '@angular/core';
import { BrowserModule} from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material';
import { LoginComponent } from './components/login/login.component';
import { StorageService } from './services/storage.service';
import { UtilsService } from './services/utils.service';
// export interface User{
// name : string;
// isOnline : boolean;
// chats : Array<Chat>;
// }
// export interface Chat {
// owners : Array<string>;
// messages : Array<Message>;
// }
// export interface Message {
// owner : string;
// message : string;
// createdAt : string;
// }
@Component({
selector: 'my-app',
templateUrl: './app/app.component.html',
styleUrl: ['./app/app.component.css']
})
export class AppComponent implements OnInit {
users : Array<any> = [];
onlineUsers : Array<any> = []
chats : Array<any> = [];
systemMessages : Array<string> = [];
constructor(
public loginDialog: MatDialog,
public loginDialogRef: MatDialogRef<LoginComponent>,
private _storageService: StorageService,
private _utilsService: UtilsService,
) {
}
ngOnInit(): void {
this.initUsers();
}
onMessageSent(data) {
let indexes = [];
_.each(this.onlineUsers, (u, index)=>{
if(_.indexOf(data.owners, u.userName) > -1) {
indexes.push(index);
}
});
_.each(indexes, (index)=>{
this.onlineUsers[index] = this._utilsService.deepCopy(this.onlineUsers[index]);
});
}
addSystemMessage(msg) {
this.systemMessages.unshift(msg);
}
onLogout(userName) {
this.onlineUsers = _.reject(this.onlineUsers, (u) => { return u.userName == userName});
this.users = this._storageService.getUsers();
this.addSystemMessage("User " + userName +" logged out!");
}
onDeleteUser(userName) {
this.onlineUsers = _.reject(this.onlineUsers, (u) => { return u.userName == userName});
this.users = this._storageService.getUsers();
this.addSystemMessage("User " + userName +" deleted!");
}
onChatAction(data):void {
if(data.action == "message_sent"){
this.onMessageSent(data);
} else if (data.action == "logout") {
this.onLogout(data.user.userName);
}
else if (data.action == "delete_user") {
this.onDeleteUser(data.user.userName);
}
}
initUsers(){
this._storageService.setAllUsersOnlineStatus(false);
}
openChat(){
let config = new MatDialogConfig();
this.loginDialogRef = this.loginDialog.open(LoginComponent, config);
this.loginDialogRef.afterClosed().subscribe(user => {
if(!user) return;
this.onlineUsers.push(user);
this.users = this._storageService.getUsers();
this.addSystemMessage("User " + user.userName +" joined to chat.");
});
}
withoutCurentUser(user) {
return _.reject(this.users, (u) => { return u.userName == user.userName});
}
resetChat() {
this.addSystemMessage("All chats and users deleted!");
this._storageService.reset();
this.users = [];
this.onlineUsers = [];
}
scrollToBottom(): void {
try {
this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;
} catch(err) { }
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { ChatComponent } from './components/chat/chat.component';
import { MatDialogModule, MatListModule, MatDialogRef, MAT_DIALOG_DATA, MatButtonModule} from '@angular/material';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/map';
import { StorageService } from './services/storage.service';
import { UtilsService } from './services/utils.service';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
MatDialogModule,
MatButtonModule,
ReactiveFormsModule,
MatListModule,
//ChatComponent,
],
declarations: [
AppComponent,
LoginComponent,
ChatComponent,
],
entryComponents: [
LoginComponent,
//ChatComponent,
],
exports : [
LoginComponent,
//ChatComponent,
],
providers: [
StorageService,
UtilsService,
{
provide: MatDialogRef,
useValue: MAT_DIALOG_DATA
},
],
bootstrap: [AppComponent]
})
export class AppModule { }
<div>
<h1>Welcome to Chat <button class="btn" (click)="openChat()">Join</button> <button class="btn" title="This will delete all chats and users" (click)="resetChat()" style="margin-left:20px;">Reset </button></h1>
<div class="system-message" #systemMessagesContainer>
<mat-list class="msgs-list">
<mat-list-item *ngFor="let m of systemMessages" >
{{m}}
</mat-list-item>
</mat-list>
</div>
</div>
<div class="" >
<mat-list class="chats-list">
<mat-list-item class="chat-item" *ngFor="let u of onlineUsers">
<app-chat name="chat" [user]="u" [users]="withoutCurentUser(u)" (notifyOnAction)="onChatAction($event)" ></app-chat>
</mat-list-item>
</mat-list>
</div>
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
import { Injectable } from '@angular/core';
import { Validators, FormControl, FormGroup } from '@angular/forms';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import { UtilsService } from './utils.service';
@Injectable()
export class StorageService {
constructor(
private _utilsService: UtilsService,
) {
}
public reset() {
localStorage.removeItem("chats");
localStorage.removeItem("chat_users");
localStorage.setItem("chats", JSON.stringify([]));
}
public deleteUser(userName) {
let users = this.getUsers();
users = _.reject(users, (u)=> { return u.userName == userName});
let chats = this.getChats();
chats = _.reject(chats, (chat)=>{ return _.indexOf(chat.owners, userName) > -1});
localStorage.setItem("chats", JSON.stringify(chats));
localStorage.setItem("chat_users", JSON.stringify(users));
}
public setAllUsersOnlineStatus(status) {
let users = this.getUsers();
_.each(users, (u)=>{ u.isOnline = status;});
this.setUsers(users)
}
public setUserOnlineStatus(userName, status) {
let users = this.getUsers();
_.each(users, (u)=>{
if(userName == u.userName) u.isOnline = status;
});
this.setUsers(users);
}
public getUserOnlineStatus(userName) {
let user = this.getUser(userName);
return user.isOnline;
}
public getUserChats(userName) {
let chats = this.getChats();
let userChats = _.reject(chats, (chat) => { return _.indexOf(chat.owners, userName) < 0 });
return this._utilsService.deepCopy(userChats, "Array");
}
public getChatByOwners(owners, chats) {
let returnACopy = false;
if(!chats) {
chats = this.getChats();
returnACopy = true;
}
let result;
_.each(chats, (chat)=>{
if(chat.owners.sort().join(',') === owners.sort().join(',')){
result = chat;
}
});
return returnACopy ? this._utilsService.deepCopy(result) : result;
}
public deleteUserChats(userName) {
let chats = this.getChats();
chats = _.reject(chats, (chat) => { return _.indexOf(chat.owners, userName) > 0 });
return this._utilsService.deepCopy(chats, "Array");
}
public getChats () : Array<any>{
let chats = localStorage.getItem("chats");
if(!chats) return [];
let chatsObj = JSON.parse(chats);
return this._utilsService.deepCopy(chatsObj, "Array");
}
public saveMessage(message, owners) {
let chats = this.getChats();
let userChats = this.getChatByOwners(owners, chats);
userChats.messages.push(message);
userChats.messages = userChats.messages.sort((a, b) => a.timestamp - b.timestamp);
this.setChats(chats);
}
public getUserData(userName) {
let interlocutors = _.reject(this.getUsers(), (user) => { return user.userName == userName});
// let interlocutors = _.reject(chatUsers, (chat) => { return _.indexOf(chat.owners, userName) < 0 });
let userChatsArray = this.getUserChats(userName);
let userChatsObj = {};
_.each(userChatsArray, (chat) => {
let interlocutor = _.find(chat.owners, (owner)=> {return owner != userName});
userChatsObj[interlocutor] = chat.messages;
});
return {interlocutors : interlocutors || [], userChats : userChatsObj || {}};
}
public getUsers() : Array<any>{
let chatUsers = localStorage.getItem("chat_users");
if (!chatUsers) return [];
else return JSON.parse(chatUsers);
}
public getOnlineUsers() {
let onlineUsers = this.getUsers();
onlineUsers = _.reject(onlineUsers, (u) => { return !u.isOnline; });
return onlineUsers;
}
public setUsers(users) {
localStorage.setItem("chat_users", JSON.stringify(users));
}
public setChats(chats) {
localStorage.setItem("chats", JSON.stringify(chats));
}
public addChat(chat) {
let chats = this.getChats();
chats.push(chat);
localStorage.setItem("chats", JSON.stringify(chats));
}
public addUser(userName) {
let user = {
userName : userName,
isOnline : true,
}
let chatUsers : Array<any> = this.getUsers();
chatUsers.push(user);
this.setUsers(chatUsers);
return this._utilsService.deepCopy(user);
}
public getUser(userName) : object {
let chatUsers = this.getUsers();
let user = _.find(chatUsers, function(u) { return u.userName == userName;});
return this._utilsService.deepCopy(user) || null;
}
}
import { Injectable } from '@angular/core';
@Injectable()
export class UtilsService {
public deepCopy (obj, convertToType?) {
if(!obj) return null;
var newObj = JSON.parse(JSON.stringify(obj));
if(convertToType == "Array") {
newObj = Array.from(newObj)
}
return newObj;
}
public scrollToBottom(scrollContainer): void {
try {
scrollContainer.nativeElement.scrollTop = scrollContainer.nativeElement.scrollHeight;
} catch(err) { }
}
public formatDate(date, format) {
return moment(date).format(format);
}
}
import { Component, OnInit} from '@angular/core'
import { MatDialog, MatDialogRef, MatDialogConfig } from '@angular/material';
import { FormBuilder, Validators, FormControl, FormGroup } from '@angular/forms';
import { StorageService } from '../../services/storage.service';
@Component({
selector: 'app-login',
templateUrl: './app/components/login/login.component.html',
styleUrl: ['../../app.component.css']
})
export class LoginComponent implements OnInit {
userName : string = "";
loginForm ;
constructor(
public dialog: MatDialog,
public dialogRef: MatDialogRef<any>,
public formBuilder: FormBuilder,
private _storageService: StorageService,
){
dialogRef.disableClose = true;
}
ngOnInit(): void {
this.loginForm = this.formBuilder.group({
userName: new FormControl('', [Validators.required]),
});
}
login(pleaseLogMeIn) {
if(!pleaseLogMeIn) {
this.closeDialog(null);
return;
}
if(!this.loginForm || !this.loginForm.get("userName") || this.loginForm.invalid){
return;
}
let userName = this.loginForm.get("userName").value;
var user = this._storageService.getUser(userName);
if(user && !user.isOnline) {
this._storageService.setUserOnlineStatus(userName, true);
this.closeDialog(user);
} else if (user && user.isOnline) {
alert("This user already logged in, please choose another address");
this.loginForm.get("userName").setValue("");
return;
}
else {
user = this._storageService.addUser(userName);
this.closeDialog(user);
}
}
closeDialog(responce){
if(this.dialogRef) this.dialogRef.close(responce);
this.dialogRef = null;
}
}
<h2 mat-dialog-title>Log In</h2>
<mat-dialog-content [formGroup]="loginForm" >
<input type="text" name="userName" required class="form-control" [formControlName]="'userName'" [placeholder] = "'Please enter Username'">
<div class="form-field-error" *ngIf="(!loginForm.controls.userName.valid && loginForm.controls.userName.touched && loginForm.controls.userName.errors.required)">Enter Username</div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button class="mat-button" (click)="login(false)">Close</button>
<button mat-button class="mat-button mat-primary" (click)="login(true)">Save</button>
</mat-dialog-actions>
import { Component, OnInit, OnDestroy, Input, EventEmitter, Output, ElementRef, ViewChild} from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import { MatDialog, MatDialogRef, MatDialogConfig } from '@angular/material';
import { FormBuilder, Validators, FormControl, FormGroup } from '@angular/forms';
import { StorageService } from '../../services/storage.service';
import { UtilsService } from '../../services/utils.service';
@Component({
selector: 'app-chat',
templateUrl: './app/components/chat/chat.component.html',
})
export class ChatComponent implements OnInit, OnDestroy {
messageForm;
subscribeToUserUpdates;
isPolling = false;
@ViewChild('msgContainer') private scrollContainer: ElementRef;
private _user;
@Input() set user (user) {
this._user = this.updateUser(user);
}
get user() {
if(this._user.prevUpdated == this._user.lastUpdated)
this._utilsService.scrollToBottom(this.scrollContainer);
return this._user;
}
private _users;
@Input() set users (users) {
let onlineUsers = _.sortBy(_.reject(users, (u) { return !u.isOnline; }), "userName");
let offlineUsers = _.sortBy(_.reject(users, (u) { return u.isOnline; }), "userName");
users = onlineUsers.concat(offlineUsers);
this._users = users;
if(this.user && !this.user.activeInterlocutor) this.setActiveInterlocutor(users[0], this.user);
}
get users() {
return this._users;
}
@Output() notifyOnAction: EventEmitter<string> = new EventEmitter<string>();
constructor(
public formBuilder: FormBuilder,
private _storageService: StorageService,
private _utilsService: UtilsService,
){
}
ngOnInit(): void {
this.messageForm = this.formBuilder.group({
message: new FormControl(),
});
}
updateUser(user) {
let userData = this._storageService.getUserData(user.userName);
user.chats = userData.userChats;
if(!user.activeInterlocutor && this.users) this.setActiveInterlocutor(this.users[0], user);
return user;
}
setActiveInterlocutor (interlocutor, user) {
if(!user || !interlocutor) return;
if(user && interlocutor && user.activeInterlocutor && user.activeInterlocutor.userName == interlocutor.userName) return;
user.activeInterlocutor = interlocutor;
if(user.activeInterlocutor && !user.chats[user.activeInterlocutor.userName]) {
let firstChat = this.createNewChat(user.userName, user.activeInterlocutor.userName);
user.chats[user.activeInterlocutor.userName] = firstChat.messages;
this._storageService.addChat(firstChat);
}
if(this.messageForm && this.messageForm.get("message")) this.messageForm.get("message").setValue("");
this._utilsService.scrollToBottom(this.scrollContainer);
}
createNewChat (user, interlocutor) {
return {
owners : [user, interlocutor],
messages : []
}
}
sendMessage() {
let message = this.messageForm && this.messageForm.get("message") ? this.messageForm.get("message").value : "";
if(!message) return;
let owners = [this.user.userName, this.user.activeInterlocutor.userName];
let messageObj = {
owner : this.user.userName,
text : message,
timestamp : new Date().toISOString(),
}
this._storageService.saveMessage(messageObj, owners);
this.messageForm.get("message").setValue("");
let data = {
action: "message_sent",
message : messageObj,
owners : owners,
}
this.notifyOnAction.emit( data);
}
logOut(){
let data = {
action: "logout",
user: this.user,
}
this._storageService.setUserOnlineStatus(this.user.userName, false);
this.notifyOnAction.emit( data);
}
deleteUser(){
let data = {
action: "delete_user",
user: this.user,
}
this._storageService.deleteUser(this.user.userName);
this.notifyOnAction.emit( data);
}
ngOnDestroy() {
}
}
<div class="chat-title" style="display: inline-block; width: 100%;">
Wellcome {{user.userName}} ! {{!users || !users.length ? "You are first user, please wait until sombody will join the chat." : "" }}{{user.activeInterlocutor ? "Chatting with " + user.activeInterlocutor.userName + " (" + (user.activeInterlocutor.isOnline ? "online" : "offline") + ")" : ""}}
</div>
<div class="users-container" *ngIf="users && users.length">
<div class="interlocutors" >
<div class="interlocutor" *ngFor="let interlocutor of users" (click)="setActiveInterlocutor(interlocutor, user)" [ngClass]="{'selected' : user.activeInterlocutor && interlocutor &&user.activeInterlocutor.userName == interlocutor.userName}">
<span [ngClass]="{'online': interlocutor.isOnline, 'offline': !interlocutor.isOnline }"></span> {{interlocutor.userName}}</div>
</div>
</div>
<div class="chat-container" *ngIf="users && users.length && user.activeInterlocutor">
<div class="messages-container" *ngIf="user && user.chats && user.chats[user.activeInterlocutor.userName]" #msgContainer >
<div class="message" *ngFor="let msg of user.chats[user.activeInterlocutor.userName]" [ngClass]="{'by-owner' : user.userName == msg.owner }">
{{msg.text}}
<span class="msg-details">({{_utilsService.formatDate(msg.timestamp, "dd/MM/YYYY, h:MM:ss")}})</span>
</div>
</div>
<div class="new-message-container">
<div [formGroup]="messageForm" class="message-form">
<input type="text" name="message" required class="form-control message-input" [formControlName]="'message'" [placeholder] = "'Start chatting ...'"/>
<button class="btn" (click)="sendMessage()">Send</button>
<br style="clear:both;"/>
</div>
<div class="actions">
<button class="btn" (click)="logOut()">LogOut</button>
<button class="btn" (click)="deleteUser()">Delete User</button>
</div>
</div>
</div>
.form-field-error {
display:block;
color: red;
}
button {
margin-right: 10px;
}
.system-message {
width: 100%;
height: 60px;
overflow-y: auto;
overflow-x: hidden;
}
.system-message .mat-list-base .mat-list-item {
color: orange;
}
.mat-list-base .mat-list-item {
height:auto !important;
}
.mat-list-base.msgs-list .mat-list-item .mat-list-item-content, .mat-list-base.msgs-list .mat-list-option .mat-list-item-content{
display: inline-block !important;
width: 100% !important;
height: 20px !important;
}
.users-container, .chat-container {
float:left;
width: 30%;
border:1px solid gray;
height: 200px;
}
.chat-container {
width: calc(70% - 10px);
margin-left: 10px;
border: none;
}
.chat-container .messages-container{
border:1px solid gray;
border-radius: 5px;
width:100%;
height:100px;
overflow-x: hidden;
overflow-y: auto
}
.chat-container .messages-container .message {
font-size: 12px;
}
.chat-container .messages-container .message.by-owner {
text-align: right;
font-style: italic;
}
.chat-container .messages-container .message .msg-details {
font-size: 10px;
color:#eee;
font-style: italic;
}
.chat-container .new-message-container {
margin-top: 10px;
}
.chat-container .new-message-container .message-form .message-input{
float: left;
width: calc(100% - 75px);
}
.chat-container .new-message-container .message-form button::after {
clear: both;
}
.chat-container .new-message-container .message-form button{
float: right;
margin:0px 0px 0px 10px;
}
.chat-container .new-message-container .actions {
margin-top:10px;
}
.mat-list-base.chats-list .mat-list-item .mat-list-item-content, .mat-list-base.chats-list .mat-list-option .mat-list-item-content{
display: inline-block !important;
width: 100% !important;
height: 250px !important;
margin-bottom:10px;
border: 1px solid black !important;
border-radius: 5px;
}
.mat-list-base.chats-list .chat-item .chat-title {
display: inline-block;
width:100%;
font-size: 14px;
text-decoration: uppercase;
color: #333;
}
.interlocutors {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
}
.interlocutors .interlocutor {
padding: 10px;
margin-bottom: 5px;
border-bottom: 1px solid #9ec3ff;
}
.interlocutors .interlocutor.selected {
background-color : #9ec3ff;
}
.interlocutors .interlocutor .online, .interlocutors .interlocutor .offline {
display: inline-block;
height: 5px;
width:5px;
border-radius: 50%;
background-color: blue;
}
.interlocutors .interlocutor .offline {
background-color: red;
}
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
paths: {
'npm:': 'https://unpkg.com/'
},
//map tells the System loader where to look for things
map: {
'app': 'app',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'@angular/material': 'npm:@angular/material/bundles/material.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/cdk': 'https://unpkg.com/@angular/cdk/bundles/cdk.umd.js',
'@angular/cdk/accordion': 'https://unpkg.com/@angular/cdk/bundles/cdk-accordion.umd.js',
'@angular/cdk/a11y': 'https://unpkg.com/@angular/cdk/bundles/cdk-a11y.umd.js',
'@angular/cdk/bidi': 'https://unpkg.com/@angular/cdk/bundles/cdk-bidi.umd.js',
'@angular/cdk/coercion': 'https://unpkg.com/@angular/cdk/bundles/cdk-coercion.umd.js',
'@angular/cdk/collections': 'https://unpkg.com/@angular/cdk/bundles/cdk-collections.umd.js',
'@angular/cdk/layout': 'https://unpkg.com/@angular/cdk/bundles/cdk-layout.umd.js',
'@angular/cdk/keycodes': 'https://unpkg.com/@angular/cdk/bundles/cdk-keycodes.umd.js',
'@angular/cdk/observers': 'https://unpkg.com/@angular/cdk/bundles/cdk-observers.umd.js',
'@angular/cdk/overlay': 'https://unpkg.com/@angular/cdk/bundles/cdk-overlay.umd.js',
'@angular/cdk/platform': 'https://unpkg.com/@angular/cdk/bundles/cdk-platform.umd.js',
'@angular/cdk/portal': 'https://unpkg.com/@angular/cdk/bundles/cdk-portal.umd.js',
'@angular/cdk/tree': 'https://unpkg.com/@angular/cdk/bundles/cdk-tree.umd.js',
'@angular/cdk/text-field': 'https://unpkg.com/@angular/cdk/bundles/cdk-text-field.umd.js',
'@angular/cdk/rxjs': 'https://unpkg.com/@angular/cdk/bundles/cdk-rxjs.umd.js',
'@angular/cdk/scrolling': 'https://unpkg.com/@angular/cdk/bundles/cdk-scrolling.umd.js',
'@angular/cdk/table': 'https://unpkg.com/@angular/cdk/bundles/cdk-table.umd.js',
'@angular/cdk/stepper': 'https://unpkg.com/@angular/cdk/bundles/cdk-stepper.umd.js',
'@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js',
'@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js',
'@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js',
'tslib': 'npm:tslib/tslib.js',
'rxjs': 'npm:rxjs',
'rxjs-compat': 'npm:rxjs-compat',
'rxjs/operators': 'npm:rxjs/operators',
'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
'rxjs': { main: 'index.js', defaultExtension: 'js' },
'rxjs/operators': {main: 'index.js', defaultExtension: 'js' }
}
});
{
"name": "@plnkr/starter-angular",
"version": "1.0.3",
"description": "Angular starter template",
"dependencies": {
"@types/underscore": "^1.8.3",
"underscore": "^1.8.3",
// "rxjs": "^5.4.2",
},
"main": "./app/main.ts",
"plnkr": {
"runtime": "system",
"useHotReload": true
}
}