29
loading...
This website collects cookies to deliver better user experience
npx create-nx-workspace --preset=empty
nx generate @nrwl/angular:lib
and enter the name of the library when prompted. We can also include either the --publishable
or --buildable
flag when generated the library. Here is good documentation from the NX team to describe the 2 flags but the gist is the --publishable
flag allows us to use the library outside of the monorepo by publishing it to npm. The --buildable
flag allows NX's build engine to make some optimizations during the build. This is all done by creating custom builder's within the monorepo.@nxtend/ionic-angular
. We can create an Ionic app by installing the package and running several commands. As a source of documentation, I found these steps at this link.npm install --save-dev @nxtend/ionic-angular
nx generate @nxtend/ionic-angular:init
nx generate @nxtend/ionic-angular:app grocery-ionic
nx serve grocery-ionic --open
.nx run grocery-ionic:add:ios
and nx run grocery-ionic:add:android
."grocery-ionic-ios": "nx build grocery-ionic && nx run grocery-ionic:sync:ios && nx run grocery-ionic:open:ios",
"grocery-ionic-android": "nx build grocery-ionic && nx run grocery-ionic:sync:android && nx build grocery-ionic:open:android"
nx generate @nrwl/angular:app grocery
nx serve grocery --open
, we will see the NX Angular template in the browser.nx generate @nrwl/angular:lib grocery-shared-business-logic --buildable
export type AppViewModel = {
headerData?: HeaderData;
itemCategories: string[];
items: GroceryItem[];
};
export interface IAppStateService {
viewModel$: Observable<AppViewModel>;
getViewModel: () => Observable<AppViewModel>;
addItemToList: (itemToAdd: FormGroup) => void;
}
export abstract class AppStateService {
protected INITIAL_STATE: AppViewModel = {
headerData: undefined,
items: [],
itemCategories: [],
};
protected viewModelSub$ = new BehaviorSubject<AppViewModel>(
this.INITIAL_STATE
);
viewModel$ = this.viewModelSub$.asObservable();
constructor(
protected headerDataService: IHeaderDataService,
protected storageSvc: IStorageUtilSvc,
protected _store: Store<AppState>
) {}
getViewModel(defaultHeaderData: HeaderData): Observable<AppViewModel> {
const loadGroceryItems$ = this.storageSvc
.getStorageItem(StorageType.GROCERY_ITEM)
.pipe(
tap((items) => {
this._store.dispatch(LoadItems({ allItems: items }));
}),
take(1),
ignoreElements()
);
const headerData$ = this.headerDataService
.getHeaderData(defaultHeaderData)
.pipe(filter((headerData) => !!headerData));
let itemCategories: string[] = Object.values(GroceryItemCategoryType);
const itemCategories$ = of(itemCategories);
const allItems$ = this._store.select(getAllItems);
const initialViewModel$ = combineLatest([
headerData$,
itemCategories$,
allItems$,
]).pipe(
map(([headerData, itemCategories, items]) => {
return { headerData, itemCategories, items };
})
);
return merge(initialViewModel$, this.viewModel$, loadGroceryItems$);
}
addItemToList(addItemForm: FormGroup): void {
const addToCurrentList = !!addItemForm.get('addToCurrentList')?.value;
const item = addItemForm.get('item')?.value;
const itemCategory = addItemForm.get('itemCategory')?.value;
const itemToAdd: GroceryItem = {
id: addToCurrentList ? this.generateItemId() : undefined,
name: item,
category: itemCategory,
datePurchased: addToCurrentList ? new Date().toDateString() : undefined
};
this.storageSvc.addGroceryItem(itemToAdd);
}
private generateItemId(): string {
return Math.random().toString(16).substr(2, 16);
}
}
export class WebAppStateService extends AppStateService
implements IAppStateService {
readonly INITIAL_STATE: AppViewModel = {
headerData: {
title: 'Current Grocery Items',
buttons: {
button: [
{
text: 'Add to list',
name: 'add',
}
],
position: HeaderButtonPosition.END,
}
},
itemCategories: [],
items: [],
};
protected viewModelSub$ = new BehaviorSubject<AppViewModel>(this.INITIAL_STATE);
constructor(
protected headerDataService: WebHeaderDataService,
protected webStorageSvc: WebStorageUtilService,
protected store: Store<AppState>
) {
super(headerDataService, webStorageSvc, store);
}
getViewModel(): Observable<AppViewModel> {
return super.getViewModel(this.INITIAL_STATE.headerData!);
}
}
export class IonicAppStateService extends AppStateService implements IAppStateService {
readonly INITIAL_STATE: AppViewModel = {
headerData: {
title: 'Current Grocery Items',
buttons: {
button: [
{
name: 'add-circle-outline',
},
],
position: HeaderButtonPosition.END,
},
},
itemCategories: [],
items: [],
};
constructor(
protected headerDataService: IonicHeaderDataService,
protected ionicStorageSvc: IonicStorageUtilService,
protected store: Store<AppState>,
private _router: Router
) {
super(headerDataService, ionicStorageSvc, store);
}
getViewModel(): Observable<AppViewModel> {
return super.getViewModel(this.INITIAL_STATE.headerData!);
}
handleAddListClickEvent(): void {
this.headerDataService.setNextHeader();
}
handleItemDetailClickEvent(item: GroceryItem): void {
this.headerDataService.setItemDetailHeader(item);
}
addItemToList(addItemForm: FormGroup): void {
super.addItemToList(addItemForm);
this._store.dispatch(SetHeader({headerData: this.INITIAL_STATE.headerData!}));
this._router.navigate(['']);
}
}
export class HomeComponent implements OnInit {
viewModel$!: Observable<AppViewModel>;
addItemForm!: FormGroup;
constructor(
public webStateServce: WebAppStateService,
private _formService: AddItemFormService
) {}
ngOnInit(): void {
this.viewModel$ = this.webStateServce.getViewModel();
this.addItemForm = this._formService.getAddItemFormGroup();
}
}
export class HomePage implements OnInit {
viewModel$!: Observable<AppViewModel>;
constructor(public stateSvc: IonicAppStateService){}
ngOnInit(): void {
this.viewModel$ = this.stateSvc.getViewModel();
}
}