TSK-178 add master and detail component
This commit is contained in:
parent
0c5ed430c8
commit
4044b8f8b3
|
@ -5,7 +5,7 @@
|
|||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": " npm run",
|
||||
"build": " ng build --env=dev",
|
||||
"build:prod": "ng build --env=prod",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
|
|
|
@ -1,27 +1,42 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AppComponent } from './app.component';
|
||||
import { WorkbasketListComponent } from './workbasket/list/workbasket-list.component';
|
||||
import { WorkbasketadministrationComponent } from './workbasketadministration/workbasketadministration.component';
|
||||
import { CategoriesadministrationComponent } from './categoriesadministration/categoriesadministration.component';
|
||||
import { MasterAndDetailComponent } from './shared/masterAndDetail/master-and-detail.component';
|
||||
|
||||
const appRoutes: Routes = [
|
||||
{ path: 'workbaskets',
|
||||
component: MasterAndDetailComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'workbaskets',
|
||||
component: WorkbasketadministrationComponent
|
||||
path: '',
|
||||
component: WorkbasketListComponent,
|
||||
outlet: 'master'
|
||||
},
|
||||
{
|
||||
path: 'workbaskets/:id',
|
||||
component: WorkbasketadministrationComponent
|
||||
path: ':id',
|
||||
component: WorkbasketadministrationComponent,
|
||||
outlet: 'detail'
|
||||
}
|
||||
]
|
||||
},
|
||||
{ path: 'clasifications',
|
||||
component: MasterAndDetailComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'categories',
|
||||
component: CategoriesadministrationComponent
|
||||
path: '',
|
||||
component: CategoriesadministrationComponent,
|
||||
outlet: 'detail'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'workbaskets',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
}
|
||||
];
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<div class="col-xs-9 col-md-7 logo-container">
|
||||
<ul class="nav nav-tabs no-border-bottom" id="myTabs" role="tablist">
|
||||
<li role="presentation" class="{{workbasketsRoute? 'active' : 'inactive'}}" role="tab" data-toggle="tab" ><a routerLink="/workbaskets" aria-controls="Work baskets" routerLinkActive="active">Workbaskets</a></li>
|
||||
<li role="presentation" class="{{workbasketsRoute? 'inactive' : 'active'}}" role="tab" data-toggle="tab" ><a routerLink="/categories" aria-controls="Clasifications" routerLinkActive="active">Clasifications</a></li>
|
||||
<li role="presentation" class="{{workbasketsRoute? 'inactive' : 'active'}}" role="tab" data-toggle="tab" ><a routerLink="/clasifications" aria-controls="Clasifications" routerLinkActive="active">Clasifications</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
|
@ -31,5 +31,3 @@
|
|||
</nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ describe('AppComponent', () => {
|
|||
{ path: 'categories', component: AppComponent }
|
||||
];
|
||||
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
|
@ -24,7 +23,6 @@ describe('AppComponent', () => {
|
|||
AngularSvgIconModule,
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
HttpClientModule
|
||||
|
||||
]
|
||||
}).compileComponents();
|
||||
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
/**
|
||||
* Modules
|
||||
*/
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule, } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpModule, JsonpModule } from '@angular/http';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AlertModule } from 'ngx-bootstrap';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||
import { TreeModule } from 'angular-tree-component';
|
||||
import { WorkbasketlistComponent } from './workbasketlist/workbasketlist.component';
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
import { AppComponent } from './app.component';
|
||||
import { WorkbasketListComponent } from './workbasket/list/workbasket-list.component';
|
||||
import { WorkbasketeditorComponent } from './workbasketeditor/workbasketeditor.component';
|
||||
import { CategorieslistComponent } from './categorieslist/categorieslist.component';
|
||||
import { CategoriestreeComponent } from './categoriestree/categoriestree.component';
|
||||
|
@ -16,25 +26,15 @@ import { WorkbasketadministrationComponent } from './workbasketadministration/wo
|
|||
import { WorkbasketAuthorizationComponent } from './workbasket-authorization/workbasket-authorization.component';
|
||||
import { WorkbasketDetailsComponent } from './workbasket-details/workbasket-details.component';
|
||||
import { WorkbasketDistributiontargetsComponent } from './workbasket-distributiontargets/workbasket-distributiontargets.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AlertModule } from 'ngx-bootstrap';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
//Shared
|
||||
import { MasterAndDetailComponent} from './shared/masterAndDetail/master-and-detail.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
WorkbasketlistComponent,
|
||||
WorkbasketeditorComponent,
|
||||
CategorieslistComponent,
|
||||
CategoriestreeComponent,
|
||||
CategoryeditorComponent,
|
||||
CategoriesadministrationComponent,
|
||||
WorkbasketadministrationComponent,
|
||||
WorkbasketAuthorizationComponent,
|
||||
WorkbasketDetailsComponent,
|
||||
WorkbasketDistributiontargetsComponent
|
||||
],
|
||||
imports: [
|
||||
|
||||
/**
|
||||
* Services
|
||||
*/
|
||||
|
||||
const MODULES = [
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpModule,
|
||||
|
@ -45,7 +45,25 @@ import { AngularSvgIconModule } from 'angular-svg-icon';
|
|||
AlertModule.forRoot(),
|
||||
AngularSvgIconModule,
|
||||
HttpClientModule
|
||||
],
|
||||
];
|
||||
|
||||
const COMPONENTS = [
|
||||
AppComponent,
|
||||
WorkbasketListComponent,
|
||||
WorkbasketeditorComponent,
|
||||
CategorieslistComponent,
|
||||
CategoriestreeComponent,
|
||||
CategoryeditorComponent,
|
||||
CategoriesadministrationComponent,
|
||||
WorkbasketadministrationComponent,
|
||||
WorkbasketAuthorizationComponent,
|
||||
WorkbasketDetailsComponent,
|
||||
WorkbasketDistributiontargetsComponent,
|
||||
MasterAndDetailComponent
|
||||
];
|
||||
@NgModule({
|
||||
declarations: COMPONENTS,
|
||||
imports: MODULES,
|
||||
providers: [HttpClientModule],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
<div class="{{showDetail? 'col-md-4 hidden-xs hidden-sm':'col-xs-12 col-md-4'}} vertical-right-divider full-height" >
|
||||
<router-outlet name="master"></router-outlet>
|
||||
</div>
|
||||
<div class="{{showDetail? 'col-xs-12 col-md-8': 'hidden'}} container-scrollable" >
|
||||
<router-outlet name="detail">
|
||||
<a class="{{showDetail? 'hidden visible-xs visible-sm': 'hidden'}}" (click) = "backClicked()"> < Back</a>
|
||||
</router-outlet>
|
||||
</div>
|
||||
<div class="{{showDetail? 'hidden': 'col-md-8 container-no-detail' }}">
|
||||
<div class = "center-block no-detail" >
|
||||
<h3>Select a worbasket</h3>
|
||||
<svg-icon class="img-responsive no-detail-icon" src="./assets/icons/no-shopping-basket.svg"></svg-icon>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
.container-no-detail .no-detail-icon {
|
||||
display: block;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
fill: grey;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.container-no-detail{
|
||||
top:30vh;
|
||||
}
|
||||
|
||||
.center-block.no-detail {
|
||||
width: 250px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
import {Location} from "@angular/common";
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { TestBed, async, inject, fakeAsync } from '@angular/core/testing';
|
||||
import { MasterAndDetailComponent } from './master-and-detail.component';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Router, Routes, ActivatedRoute, NavigationStart, RouterEvent } from '@angular/router';
|
||||
import { AngularSvgIconModule } from 'angular-svg-icon';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
@Component({
|
||||
selector: 'dummy-master',
|
||||
template: 'dummymaster'
|
||||
})
|
||||
export class DummyMasterComponent {
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'dummy-detail',
|
||||
template: 'dummydetail'
|
||||
})
|
||||
export class DummyDetailComponent {
|
||||
|
||||
}
|
||||
|
||||
describe('MasterAndDetailComponent ', () => {
|
||||
|
||||
var component, fixture, debugElement, location, router;
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'workbaskets',
|
||||
component: MasterAndDetailComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: DummyMasterComponent,
|
||||
outlet: 'master'
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
component: DummyDetailComponent,
|
||||
outlet: 'detail'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ MasterAndDetailComponent, DummyMasterComponent, DummyDetailComponent ],
|
||||
imports:[
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
AngularSvgIconModule,
|
||||
HttpClientModule
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MasterAndDetailComponent);
|
||||
component = fixture.debugElement.componentInstance;
|
||||
debugElement = fixture.debugElement.nativeElement;
|
||||
location = TestBed.get(Location);
|
||||
router = TestBed.get(Router);
|
||||
router.initialNavigation();
|
||||
|
||||
}));
|
||||
|
||||
afterEach(async(()=>{
|
||||
document.body.removeChild(debugElement);
|
||||
}));
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should call Router.navigateByUrl("/wokbaskets") and showDetail property should be false', async ( () => {
|
||||
|
||||
expect(component.showDetail).toBe(false);
|
||||
fixture.detectChanges();
|
||||
router.navigateByUrl('/workbaskets');
|
||||
expect(component.showDetail).toBe(false);
|
||||
|
||||
}));
|
||||
|
||||
it('should call Router.navigateByUrl("/wokbaskets/(detail:Id)") and showDetail property should be true', async ( () => {
|
||||
|
||||
expect(component.showDetail).toBe(false);
|
||||
fixture.detectChanges();
|
||||
router.navigateByUrl('/workbaskets/(detail:2)');
|
||||
expect(component.showDetail).toBe(true);
|
||||
|
||||
}));
|
||||
|
||||
it('should navigate to parent state when backIsClicked', async( () => {
|
||||
|
||||
const spy = spyOn(router, 'navigateByUrl');
|
||||
router.navigateByUrl('/workbaskets/(detail:2)');
|
||||
fixture.detectChanges();
|
||||
expect(spy.calls.first().args[0]).toBe('/workbaskets/(detail:2)');
|
||||
component.backClicked();
|
||||
expect(spy.calls.mostRecent().args.length).toBe(2);
|
||||
|
||||
}));
|
||||
|
||||
});
|
|
@ -0,0 +1,46 @@
|
|||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Router, Routes, ActivatedRoute, NavigationStart, RouterEvent } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'master-and-detail',
|
||||
templateUrl: './master-and-detail.component.html',
|
||||
styleUrls: ['./master-and-detail.component.scss'],
|
||||
|
||||
})
|
||||
export class MasterAndDetailComponent implements OnInit{
|
||||
private detailRoutes: Array<string> = ['/workbaskets/(detail', 'clasifications'];
|
||||
private sub: any;
|
||||
|
||||
showDetail: Boolean = false;
|
||||
constructor(private route: ActivatedRoute, private router: Router){
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.showDetail = this.showDetails();
|
||||
this.router.events.subscribe(event => {
|
||||
if(event instanceof NavigationStart) {
|
||||
this.showDetail = this.showDetails(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
backClicked(): void {
|
||||
this.router.navigate(['../'], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
private showDetails(event? : RouterEvent): Boolean {
|
||||
if(event === undefined) {
|
||||
return this.checkUrl(this.router.url);
|
||||
}
|
||||
return this.checkUrl(event.url)
|
||||
}
|
||||
|
||||
private checkUrl(url: string): Boolean {
|
||||
for(let routeDetail of this.detailRoutes){
|
||||
if(url.indexOf(routeDetail) !== -1){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,8 @@
|
|||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngFor="let workbasket of workbaskets" (click)="onSelect(workbasket)" [class.active]="workbasket.id == selected.id" [routerLink]="['/workbaskets', workbasket.id]">
|
||||
|
||||
<tr *ngFor="let workbasket of workbaskets" (click)="onSelect(workbasket)" [class.active]="workbasket.id == selected.id" [routerLink]="[ {outlets: { detail: [workbasket.id] } }]">
|
||||
<td *ngIf="workbasket.id != editing.id">{{ workbasket.id }}</td>
|
||||
<td *ngIf="workbasket.id == editing.id">
|
||||
<input class="form-control" placeholder="Id" name="editid" [(ngModel)]="editing.id" readonly>
|
|
@ -1,20 +1,20 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { WorkbasketlistComponent } from './workbasketlist.component';
|
||||
import { WorkbasketListComponent } from './workbasket-list.component';
|
||||
|
||||
describe('WorkbasketlistComponent', () => {
|
||||
let component: WorkbasketlistComponent;
|
||||
let fixture: ComponentFixture<WorkbasketlistComponent>;
|
||||
describe('WorkbasketListComponent', () => {
|
||||
let component: WorkbasketListComponent;
|
||||
let fixture: ComponentFixture<WorkbasketListComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ WorkbasketlistComponent ]
|
||||
declarations: [ WorkbasketListComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(WorkbasketlistComponent);
|
||||
fixture = TestBed.createComponent(WorkbasketListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
|
@ -1,16 +1,16 @@
|
|||
import { Component, OnInit, EventEmitter } from '@angular/core';
|
||||
import { Workbasket } from '../model/workbasket';
|
||||
import { WorkbasketserviceService } from '../services/workbasketservice.service'
|
||||
import { Workbasket } from '../../model/workbasket';
|
||||
import { WorkbasketserviceService } from '../../services/workbasketservice.service'
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-workbasketlist',
|
||||
selector: 'workbasket-list',
|
||||
outputs: ['selectedWorkbasket'],
|
||||
templateUrl: './workbasketlist.component.html',
|
||||
styleUrls: ['./workbasketlist.component.css'],
|
||||
templateUrl: './workbasket-list.component.html',
|
||||
styleUrls: ['./workbasket-list.component.css'],
|
||||
providers: [WorkbasketserviceService]
|
||||
})
|
||||
export class WorkbasketlistComponent implements OnInit {
|
||||
export class WorkbasketListComponent implements OnInit {
|
||||
public selectedWorkbasket: EventEmitter<Workbasket> = new EventEmitter();
|
||||
|
||||
workbasket: Workbasket = this.getEmptyObject();
|
|
@ -1,2 +1,3 @@
|
|||
<!-- app-workbasketeditor [workbasket]="selectedWorkbasket" (workbasketSaved)="onWorkbasketSaved($event)"></app-workbasketeditor -->
|
||||
<app-workbasketlist (selectedWorkbasket)="onWorkbasketSelected($event)"></app-workbasketlist>
|
||||
<!-- <workbasket-list (selectedWorkbasket)="onWorkbasketSelected($event)"></workbasket-list> -->
|
||||
DETAIL COMPONENT
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.314 16.935c.856 0 1.544.84 1.544 1.885 0 1.046-.688 1.885-1.545 1.885h-.18l-1.39 9.747c-.132.898-.772 1.56-1.52 1.56h-15.45c-.749 0-1.388-.662-1.521-1.56l-1.388-9.747h-.181c-.857 0-1.545-.84-1.545-1.885 0-1.046.688-1.885 1.545-1.885zm-17.322 11.78c.422-.045.748-.5.712-1.016l-.386-6.126c-.036-.515-.41-.912-.833-.868-.422.044-.748.5-.712 1.016l.386 6.125c.036.486.374.869.772.869zm4.96-.943v-6.125c0-.515-.35-.942-.772-.942-.422 0-.773.427-.773.942v6.125c0 .516.35.943.773.943.423 0 .773-.427.773-.943zm4.636 0v-6.125c0-.515-.35-.942-.773-.942-.422 0-.772.427-.772.942v6.125c0 .516.35.943.772.943.423 0 .773-.427.773-.943zm4.249.074l.386-6.125c.036-.516-.29-.972-.712-1.016-.423-.044-.797.353-.833.868l-.386 6.126c-.037.515.29.971.712 1.016h.06c.399 0 .737-.383.773-.869zM12.883 9.926l-1.122 6.067h-1.594l1.22-6.494c.313-1.722 1.557-2.93 3.005-2.93h2.016c0-.515.35-.942.773-.942h4.634c.423 0 .773.427.773.942h2.016c1.448 0 2.692 1.208 3.006 2.93l1.219 6.494h-1.594l-1.122-6.066c-.17-.87-.785-1.473-1.51-1.473h-2.015c0 .515-.35.942-.773.942h-4.634c-.423 0-.773-.426-.773-.942h-2.016c-.724 0-1.34.604-1.509 1.473zM2.28.11l2.806 3.237L7.878.124a.327.327 0 0 1 .51.002l1.53 1.766c.14.162.141.425 0 .587L7.127 5.7 9.932 8.94c.14.162.141.425.001.587l-1.524 1.758a.327.327 0 0 1-.509-.001L5.094 8.046l-2.793 3.222a.327.327 0 0 1-.509-.001L.262 9.5a.462.462 0 0 1-.002-.587L3.053 5.69.247 2.453a.462.462 0 0 1 0-.587L1.77.108a.327.327 0 0 1 .509.002z"/></svg>
|
After Width: | Height: | Size: 1.5 KiB |
Loading…
Reference in New Issue