implementation of loader in Angular 8 - angular8

Can anyone help me in implementing loader as I am new in angular(angular 8). I am able to show sequence of data in section wise, but loader is being rotated whereas data has already been came up, but requirement is once data being displayed, loader must get removed.
<ng-container *ngFor=" let memoSectionName of memoData?.sections">
<div class="divhorizontalspacebetween greybg _1emgapbelow">
<div class="labelsmall weight700">{{memoSectionName?.display_name}}</div>
<!-- <div class="actionbutton">
<img src="./assets/images/actions-edit.svg" loading="lazy" alt="" (click)="openEditBasicInfo(); openEditSection('projectInfo')">
</div> --> </div> <ng-container *ngFor="let card_details of memo_card_details"> <div *ngIf="memo_list?.length != memo_card_details?.length" style="justify-content: center; align-items: center; display:flex">
<app-custom-loader>
</app-custom-loader>
</div>
<ng-container *ngFor="let card of card_details.card_data">
<ng-container *ngIf="card?.master_name == 'Project and Project Narrative' && card?.master_name == memoSectionName?.master_name">
<div>
<div>

Create a Loader Service
import { Injectable } from "#angular/core";
#Injectable({
providedIn: "root",
})
export class LoaderService {
constructor() {}
Show(div: string): void {
let findDiv = document.getElementById(div);
if (findDiv) {
document
.getElementById(div)
.insertAdjacentHTML(
"afterbegin",
`<div class="loader-holder"><div class="loader"></div></div>`
);
document.getElementById(div).classList.add("loader-mask");
}
}
Hide(div): void {
let findDiv = document.getElementById(div);
if (findDiv) {
let loader = this.FindLoader(div);
if (loader) {
loader.remove();
}
document.getElementById(div).classList.remove("loader-mask");
}
}
FindLoader(containerID): Element {
let elm = document.getElementsByClassName("loader-holder");
let parent: any = elm && elm.length > 0 ? elm[0].parentNode : {};
return parent.id && parent.id === containerID ? elm[0] : null;
}
}
In your HTML give an Id to your div where you want to apply loader
<div id="loader-display-id">
......
</div>
In your Typescript class Inject Service and call methods
LoaderId : string = "loader-display-id";
constructor(private loader : LoaderService)
{
}
getDetails() : void
{
this.loader.Show(this.LoaderId);
//Perform Necessary Actions
this.loader.Hide(this.LoaderId);
}

Related

vue component compilation issue

I'm pretty new to Vue.js so bear with me. I'm working on a project where I created two new vue components, one is a tab/toggle element, the other is a cookie banner. However, when both are added to the page the cookie banner does not compile. The HTML is rendered but it still contains all the vue syntax in its uncompiled form. Does anyone see where the conflict is occurring between these two components? I don't see any errors in the console so I'm at a loss on how to begin debugging.
Component 1:
(function () {
var _instance = new Vue({
el: "#multiTrackSwiper",
data: {
tabs: {}
},
methods: {
checkActiveTab: function (index) {
if (this.tabs['active']) {
return this.tabs['active'] === index;
} else {
return index === "0";
}
},
handlerActiveTab: function (index) {
Vue.set(this.tabs, 'active', index);
}
}
});
})();
#using Sitecore.Feature.Media.Models.Components
#model List<ITrackWithCarousel>
#if (Model != null && Model.Count > 0)
{
if (Model.Count == 1)
{
<div class="c-product-details__track">
#Html.Partial("TrackWithCarousel", Model[0])
</div>
}
else
{
var index = 0;
<div id="multiTrackSwiper" class="multi-track-swiper" vue-instance v-cloak>
<ul class="nav nav-tabs">
#foreach (var track in Model)
{
<li class="nav-item">
<button id="tab_#track.Name.Replace(" ","_")" data-bs-toggle="tab" class="nav-link"
v-bind:class="{ 'active':checkActiveTab('#index') }"
v-on:click="handlerActiveTab('#index')">
#track.DisplayName
</button>
</li>
index++;
}
</ul>
#{ index = 0; }
#foreach (var track in Model)
{
<div class="c-product-details__track c-product-details__multitrack" aria-labelledby="tab_#track.Name.Replace(" ","_")"
v-bind:class="{ 'active':checkActiveTab('#index') }">
#Html.Partial("TrackWithCarousel", track)
</div>
index++;
}
</div>
}
}
Component 2:
(function () {
var _instance = new Vue({
el: "#cookie-banner",
data: {
cookieSaved: null
},
methods: {
saveSessionCookie: function () {
var expiry = (new Date(Date.now() + 600 * 1000)).toUTCString(); // 3 days 259200
document.cookie = "cookie-banner-closed=true; expires=" + expiry + ";path=/;"
this.cookieSaved = true;
}
},
mounted: function () {
if (document.cookie.includes('cookie-banner-closed')) {
this.cookieSaved = true;
} else {
this.cookieSaved = null;
}
}
});
})();
<div id="cookie-banner" vue-instance v-cloak>
<div class="cookie-disclaimer" v-if="!cookieSaved">
<div id="cookie-notice">
<div class="cookie-inner-module h-spacing">
This website uses cookies. We do this to better understand how visitors use our site and to offer you a more personal experience. We share information about your use of our site with social media and analytics partners in accordance with our Privacy Notice</a>.
<i class="fas fa-times" v-on:click="saveSessionCookie"></i>
</div>
</div>
</div>
</div>
I've tried switching both vue components into vue instances instead but that doesn't resolve the issue.
The HTML is rendered but it still contains all the vue syntax in its uncompiled form.
I don't think that you are using Vue format/syntax. So it will render what you are typed inside html.

Angular Firestore - Display the data of the document id (View Contact

How can I display all the data on document, i got the id but i cant display the data
this is the service:
getContact(){
return this.firestore.doc('contact').get()
}
this is the view-contact component:
export class ViewContactComponent implements OnInit {
// Observable which will hold an array of Article
// contacts$: Observable<IContact[]>;
// #Input() contact: IContact
contact:IContact
id: String;
constructor(private route: ActivatedRoute,
private contactService: ContactService,private firestore: AngularFirestore) {
}
ngOnInit(): void {
// query Firestore using 'id' when page loads
// this.firestore.doc('contact/' + this.id).valueChanges();
const id = this.route.snapshot.paramMap.get('id');
this.contactService.getContact(id).subscribe(contact => {
this.contact = contact
});
console.log(id)
}
}
this is the model
export default interface IContact{
id:string | null,
name:string,
email:string,
phoneNumber:string
}
and this is the view contact template where it needs to be display, i also included the id on routing
<div *ngIf="contact" class="card shadow-sm p-3 mb-5 bg-body " style="width: 18rem;">
<div class="card-body">
<p class="text-justify">
<b>Name:{{contact.name}}</b><br>
<b>Email:{{contact.email}}</b><br>
<b>Contact Number:</b><br>
</p>
</div>
</div>

Angular2 Service which create, show and manage it's inner Component? How to implement js alert()?

I tried to find a way for having and manage an angular2 Component in a Service but with no success:
I need to create:
AlertService{
alertConfirm(msg): Promise;
}
alertConfirm will prompt an Confirmation window with 2 buttons (Ok, Cancel) and will return users' choise as a Promise.
In General, the idea is to implement the famous JavaScript alert() method
but with a designed UI window and with also a cancel button.
The method will return a Promise with a response of user's choice: "OK" or "Cancel".
I tried to find a way for holding an "anonymous" component, AlertComponent, in AlertService:
AlertComponent{
showMsgConfirm(msg): Promise;
}
The Promise will be set with a response when user close prompt window or click "OK" or "Cancel".
The question:
How to make "AlertService" to have an inner "AlertComponent" which can be managed by it's "alertOK" method?
I mean, I didn't find a way for "alertConfirm" to call "showMsgConfirm" method and to return it's Promise as a response.
for example, calling from main app component:
this.alertService.alertConfirm("Save changes?").then(res => {
if(res.ok){console.log("Can be saved");
}, err=> { });
Any ideas for this?
Thanks,
Update:2 different ideas for solution, but with no sucess to manage the AlertComponent:
import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef } from '#angular/core';
import { AlertComponent } from './../components/modales/AlertComponent/AlertComponent.component';
#Injectable()
export class AlertService {
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
public createAlertComp(vCref: ViewContainerRef): ComponentRef<any> {
let factory = this.componentFactoryResolver.resolveComponentFactory(AlertComponent);
/*
//Option 1:
// vCref is needed cause of that injector..
let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector);
// create component without adding it directly to the DOM
let comp = factory.create(injector);
// add inputs first !! otherwise component/template crashes ..
comp.instance.model = modelInput;
// all inputs set? add it to the DOM ..
vCref.insert(comp.hostView);
return comp;
*/
//Option 2:
var componentRef: ComponentRef<AlertComponent> = vCref.createComponent(factory);
return null;
}
}
And the answer is... :
The Service:
_counter is used for each modal to have a unique name.
comp.instance.close is a property of inner component for subscribing for EventEmitter.
.
import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef, EventEmitter } from '#angular/core';
import { CtmAlertComponent } from './ctmAlert/ctmAlert.component';
#Injectable()
export class AlertCtmService {
private _vcr: ViewContainerRef;
private _counter: number = 0;
constructor(private componentFactoryResolver: ComponentFactoryResolver, public viewRef: ViewContainerRef) {
console.log("AlertCtmService.constructor:");
//TODO: Consider appending to this.viewRef: "#alertCtmServiceContainer" as a Dom elemnt perent container which will hold all AlertModals:
// Maybe by:
// this.viewRef.element.nativeElement.insertAdjacentHTML('beforeend', '<div class="alertCtmServiceContainer"></div>');
this._vcr = this.viewRef;
}
public alertOK(alertMsg: string): EventEmitter<any> {
return this.createEventEmitterComponent("CtmAlertComponent", alertMsg, false);
}
public alertConfirm(alertMsg: string): EventEmitter<any> {
return this.createEventEmitterComponent("CtmAlertComponent", alertMsg, true);
}
private createEventEmitterComponent(componentName: string, alertMsg: string, isConfirm: boolean): EventEmitter<any> {
console.log("AlertCtmService.createEventEmitterComponent:");
switch (componentName) {
case "CtmAlertComponent":
default:
var _component = CtmAlertComponent;
break;
}
let factory = this.componentFactoryResolver.resolveComponentFactory(_component);
// vCref is needed cause of that injector..
let injector = ReflectiveInjector.fromResolvedProviders([], this._vcr.parentInjector);
// create component without adding it directly to the DOM
let comp = factory.create(injector);
// add inputs first !! otherwise component/template crashes ..
comp.instance.close.subscribe(resp => {
console.log("AlertCtmService.createEventEmitterComponent: comp.instance.close.subscribe: resp=" + resp.ok);
comp.destroy();
})
comp.instance.alertBodyMsg = alertMsg;
comp.instance.isConfirm = isConfirm;
comp.instance.nameId = "Modal" +(++this._counter).toString();
// all inputs set? add it to the DOM ..
this._vcr.insert(comp.hostView);
//return null;
return comp.instance.close;
}
public init(vCref: ViewContainerRef): ViewContainerRef {
this._vcr = vCref;
return this._vcr;
}
}
Inner Component:
Using Bootstrap for handling display of Modal in UI: modal('show') \ modal('hide').
.
import { Component, AfterViewInit, Input, ViewChild, ElementRef, Renderer, NgZone, EventEmitter} from '#angular/core';
#Component({
selector: 'ctm-alert',
styles: [``],
templateUrl: '/app/shared/alertCtm/ctmAlert/CtmAlert.component.html',
styleUrls: ['./app/shared/alertCtm/ctmAlert/CtmAlert.component.css'],
providers: []
})
export class CtmAlertComponent implements AfterViewInit {
public ModalIsVisible: boolean;
//private static subscriptions: Object = {};
//enums = Enums;
close = new EventEmitter();
public nameId = "";
private isOk = false;
alertBodyMsg: string = "";
isConfirm = false;
constructor() {
console.log("CtmAlertComponent.constructor:");
}
ngAfterViewInit() {
this.showModal();
var attrId = this.getIdAttr();
$('#' + attrId).on('hidden.bs.modal', function () {
debugger;
console.log('CtmAlertComponent: #licenseModal_XXX.on(hidden.bs.modal)');
this.submitStatus();
}.bind(this) );
}
showModal() {
this.ModalIsVisible = true;
var attrId = '#' +this.getIdAttr();
$(attrId).modal('show');
}
hideModal() {
this.ModalIsVisible = false;
var attrId = '#' + this.getIdAttr();
$(attrId).modal('hide');
}
getIdAttr(): string {
return "ctmAlertModal_" + this.nameId;
}
submitStatus() {
var resp = { ok: (this.isOk == true) };
this.close.emit(resp);
}
submitOk() {
this.isOk = true;
this.hideModal();
}
submitCancel() {
this.isOk = false;
this.hideModal();
}
}
App's Declaration:
unfortunately, we must declare the anonymus component in our main-app module.
We must add a declaration of entryComponents: [CtmAlertComponent],
.
import { CtmAlertComponent } from './shared/alertCtm/ctmAlert/ctmAlert.component';
#NgModule({
imports: [
BrowserModule,
HttpModule,
AppRoutingModule,
...
],
declarations: [
CtmAlertComponent,
AppComponent,
...
],
entryComponents: [CtmAlertComponent],
providers: [
...
],
bootstrap: [AppComponent],
})
export class AppModule { }
enableProdMode();
Modal UI:
this html template is based on bootstrap's UI:
.
<div class="ctmAlertModal modal fade in" [id]="getIdAttr()" role="dialog">
<div class="modal-dialog modal-lg" [ngClass]="{'modal-lg-6': true }">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header" style="">
<div class="pull-right" style="position: relative;">
<span class="fa fa-times-circle" aria-hidden="true" style="color: #949494"></span>
</div>
</div>
<div class="modal-body">
<div class="modal-body-msg">
{{alertBodyMsg}}
</div>
<div class="modal-body-buttons">
<div style="margin: 0 auto;" [style.width]="(isConfirm)? '165px' : '70px' ">
<button type="button" *ngIf="isConfirm" class="btn-submit pull-left btn-cancel" [ngClass]="{'disabled': false }" [disabled]="false" (click)="submitCancel()">
<!--<img alt="End-Training" class="centering-me2" src="../../../contents/training_state_stop_white.svg">-->
Cancel
</button>
<button type="button" class="btn-submit pull-right" [ngClass]="{'disabled': false }" [disabled]="false" (click)="submitOk()">
<!--<img alt="Resume-Training" src="../../../contents/training_state_play_white.svg">-->
OK
</button>
</div>
</div>
</div>
</div>
</div>
</div>
.
Usage::
for example:
.
this.alertCtmService.alertOK("Save changes???").subscribe(function (resp) {
console.log("alertCtmService.alertOK.subscribe: resp=" + resp.ok);
this.saveData();
}.bind(this) );
**
An example I built : https://plnkr.co/qc1ZM6
**
sources:
building-angular-2-components-on-the-fly-a-dialog-box-example
angular2-ngmodule

Enhance Aurelia model to handle dynamically loaded HTML

I have this view:
<template>
<require from="../customElements/spinner.html"></require>
<div class="sub-submenu-wrapper">
<div show.bind="success">
<div class="sub-submenu-header">
<a href="#/roommanage">
<div class="sub-submenu-header-top">
<i class="fa fa-chevron-left sub-submenu-header-top-icon"></i>
</div>
</a>
<div class="sub-submenu-header-bottom">
<h2>Manage Rooms</h2>
</div>
</div>
<div class="sub-submenu-content">
<div class="managerooms-wrapper">
<table id="tableData" class="stripe row-border cell-border"></table>
</div>
</div>
</div>
<div class="sub-submenu-loading" show.bind="!success">
<spinner></spinner>
</div>
</div>
And here is the model:
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';
import {Router} from 'aurelia-router';
import 'isomorphic-fetch';
import {appState} from '../appState';
import 'jquery';
import 'datatables.net';
#inject(HttpClient, Router, appState)
export class ManageRooms{
tableData = [];
success = false;
constructor(http, router, appstate){
this.http = http;
this.router = router;
this.jsonobj = {
'operation':'getrooms'
};
}
attached(){
this.http.fetch('assets/api/api.php', {
method: 'post',
body: JSON.stringify(this.jsonobj)
})
.then(response => response.json())
.then(data => {
if (data.error==='true') {
console.log(data.errortype);
}else {
for(var i = 0; i < data.length; i++){
this.tableData.push(
{
0: "<div>"+data[i].roomno+"</div>",
1: "&nbsp"+data[i].roomtype,
2: "<div>"+(data[i].booked ? 'Yes':'No')+"</div>",
3: "<div class='actionButtonsArea'>"
+"<a href='1'><i class='fa fa-eye fa-bot'></i></a>"
+"<a href='1'><i class='fa fa-edit fa-bot'></i></a>"
+"<a href='3'><i class='fa fa-remove fa-bot'></i></a>"
+"<a href='4'><i class='fa fa-trash-o fa-bot'></i></a>"
+"</div>"
}
);
}
$('#tableData').DataTable({
autoWidth: false,
data: this.tableData,
columns: [
{title: "Room No"},
{title: "Type"},
{title: "Occupied"},
{title: "Action"}
]
}
);
this.success = true;
}
})
.catch(response =>{
});
}
detached(){
$('#tableData').DataTable().destroy("remove");
}
}
In summary, I am making a fetch call, getting some data, making a table from it. What i want is to make the HTML data(i.e. table) that I am inserting bindable or connected to my view model. I found some information about Aurelia's enhancement here: http://ilikekillnerds.com/2016/01/enhancing-at-will-using-aurelias-templating-engine-enhance-api/ but i have trouble figuring out how to integrate this with my own code.
Overview
Prerequisite: have some already-working aurelia app
Import the TemplatingEngine
Insert your dynamic html into the DOM (e.g. via .innerHTML)
Call TemplatingEngine.enhance(config) with proper configuration
Details
Prerequisite - Create the skeleton:
au new enhance_test
I'm using the minimal example, using the skeleton provided in Aurelia CLI.
The actual code:
app.html:
<template>
<h1>${message}</h1>
<div id="content-div"></div>
</template>
app.ts:
import {autoinject, TemplatingEngine} from 'aurelia-framework';
#autoinject
export class App {
message = 'Hello World!';
constructor(private _templEngine: TemplatingEngine) { }
attached() {
let contentDivElem = document.getElementById("content-div");
contentDivElem.innerHTML = "<button>TEST ${message}</button>"; //inserting your dynamic HTML
let elemView = this._templEngine.enhance({ element: contentDivElem, bindingContext: this}); //binding the element to the instance of App
}
}

Two way binding not working on bootstrap-select with aurelia

I have managed to create a custom element to use the boostrap-select element. However, I can pass/bind values to it from the main view (parent) but I am unable to get the selection out from the element when I use two-way binding.
My custom element is:
import {inject, customElement, bindable} from 'aurelia-framework';
import * as selectpicker from 'bootstrap-select'
#customElement('select-picker')
export class BootStrapSelectPicker {
#bindable selectableValues = null;
#bindable newValue = null;
#bindable selectedValue = 10;
constructor(){
}
attached(){
$('.selectpicker').selectpicker({
style: 'btn-info',
size: 4
});
$('.selectpicker').on('change', function(){
var selected = $(this).find("option:selected").val();
this.selectedValue = selected;
console.log(this.selectedValue);
});
$('.selectpicker').val(this.selectedValue); <-- the selection here is correct
$('.selectpicker').selectpicker('refresh');
}
}
The corresponding view is:
<template>
<select class="selectpicker">
<option repeat.for="p of selectableValues">${p}</option>
</select>
</template>
My containing view that uses the custom element is:
<template>
<require from="./select-picker"></require>
<ul class="list-group">
<li class="list-group-item" repeat.for="p of messageProperties">
<div if.bind="p.propertyType == 'string'">
<div class="form-group">
<label for="ln">Name: ${p.propertyName}</label>
<input type="text" value.bind="p.propertyValue" class="form-control" id="ln" >
</div>
</div>
<div if.bind="p.propertyType == 'integer'">
<div class="form-group">
<label for="ln">Name: ${p.propertyName}</label>
<input type="text" value.bind="p.selectedValue" class="form-control" id="ln" >
<select-picker selectable-values.bind="p.selectableValues"
selected-value.two-way="p.selectedValue"></select-picker>
</div>
</div>
</li>
</ul>
</template>
I expected p.selectedValue to change once a selection is made with the select control as shown here with the two-way command:
selected-value.two-way="p.selectedValue"
However, p.selectedValue is not changing.
Any ideas why this is not working?
Turns out to be a simple scope issue:
attached(){
$('.selectpicker').selectpicker({
style: 'btn-info',
size: 4
});
$('.selectpicker').on('change', function(){
var selected = $(this).find("option:selected").val();
this.selectedValue = selected; // <-- This here doesn't refer to the VM any more
// if you look at the line above you are wrapping $(this) with jq, this works
// because 'this' is now in the scope of the calling element but
// doesn't refer to the aurelia viewmodel
console.log(this.selectedValue);
});
$('.selectpicker').val(this.selectedValue);
$('.selectpicker').selectpicker('refresh');
}
Simple fix is:
attached(){
var self = this; // <--- Create a ref to the VM
$('.selectpicker').selectpicker({
style: 'btn-info',
size: 4
});
$('.selectpicker').on('change', function(){
var selected = $(this).find("option:selected").val();
// Change this to self
self.selectedValue = selected; // <--- Correct object gets the value now - binding works
console.log(this.selectedValue);
});
$('.selectpicker').val(this.selectedValue);
$('.selectpicker').selectpicker('refresh');
}
I'm not sure how this will actually be handled in ES6/7 - I'm sure I read somewhere about how this will change, but since you are transpiling to ES5 it's definitely something to watch out for
The following code works for me, in case anyone has the same issue:
import {inject, customElement, bindable} from 'aurelia-framework';
import 'bootstrap-select'
#customElement('select-picker')
#inject(Element)
export class BootStrapSelectPicker {
#bindable name: string;
#bindable selectableValues;
#bindable selectedValue;
constructor(private element) {
}
attached() {
var self = this;
var $: any = jQuery;
var $elm = $(self.element).find('select');
if ($elm.length > 0) {
$elm.selectpicker();
$elm.on('change', function () {
self.selectedValue = $(this).find("option:selected").val();
});
this.refreshPicker($elm);
}
}
selectedValueChanged(newValue, oldValue) {
var $: any = jQuery;
var $elm = $(this.element).find('select');
this.refreshPicker($elm);
}
private refreshPicker = ($elm) => {
$elm.val(this.selectedValue);
$elm.selectpicker('refresh');
}
}