How to show/hide ng4-spinner-loader on model only angular 4/6/7? - angular6

I want to show a loader on pop-up/model once a HTTP request triggers and hide it when all http requests are completed.
I am new to angular and I am not able to find a way to implement it.
My app.html:
<ng4-loading-spinner [threshold]="2000" [template]="template" [loadingText]="'Please wait...'" [zIndex]="9999"> </ng4-loading-spinner>
app.ts
this.spinnerService.show();
I am using import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';

It depends on the scope. If the request is inside of a component or will be called in a service instance of a component, then you can set an *ngIf with a flag variable on true on the loading spinner before it starts and after the response arrives you set the variable to false:
HTML
<ng4-loading-spinner *ngIf="isLoading"></ng4-loading-spinner>
TS:
getData() {
this.isLoading = true;
this.httpClient.get(...).subscribe(
() => {
this.isLoading = false;
}
);
}

Related

how to access a component with url with parameter and without parameter in Angular

I want to implement accessing one component with two url like
first : "helloworld/search"
second : "helloworld/search/tag"
both take me on same page. with both url it should to call two different function
You can listen to router events in the component
`this.router.events.forEach((event: NavigationEvent) => {
if (event instanceof NavigationStart) {
if (event.url.toLowerCase().endsWith("/tag")) {
//one function
}else {
ther function
}
}`

How to update the html page view after a timeout in Angular

I am trying to display a routerlink name based on a condition. I want to display the div section routerLink name if condition is true.If i check {{isNameAvailable}}, first it displays false and after this.names got the values it shows true.Since in the component getDetails() method is asynchronous this.names getting the values after html template render.Therefore this routerLink does n't display.Therefore I want to display div section after some time. (That 's the solution i have) Don't know whether is there any other solution.
This is my html file code.
<main class="l-page-layout ps-l-page-layput custom-scroll bg-white">
{{isNameAvailable}}
<div class="ps-page-title-head" >
<a *ngIf ="isNameAvailable === true" [routerLink]="['/overview']">{{Name}}
</a>
{{Name}}
</div>
</main>
This is my component.ts file
names= [];
isNameAvailable = false;
ngOnInit() {
this.getDetails()
}
getDetails() {
this.route.params.subscribe(params => {
this.names.push(params.Names);
console.log(this.names);
this.getValues().then(() => {
this.isNameAvailable = this.checkNamesAvailability(this.names);
console.log(this.isNameAvailable);
});
});
}
resolveAfterSeconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 900);
});
}
checkNamesAvailability(names) {
console.log(names);
return names.includes('Sandy');
}
async getValues() {
await this.resolveAfterSeconds(900);
}
And console.log(this.isLevelAvailable); also true. What I can do for this?
1.You do not have anything to show in the HTML only the isNameAvailable, because you do not have any assignment in the Name variable.
2.It is better to use the angular build-in async pipe,
when you want to show the returned value from observables.
3.When you are using the *ngIf directive you can skip *ngIf ="isNameAvailable === true" check because the variable is boolean type, you gust write *ngIf ="isNameAvailable", it will check also for null but NOT for undefined
It is working because the *ngIf directive is responsible for checking and rendering the UI, you can see how many times the directive is checking by calling an function and print and answer in the console.
By any chance do you have changeDetection: ChangeDetectionStrategy.OnPush docs set in component annotation? That might explain this behaviour. With it Angular run change detection only on component #Input()'s changes and since in your case there were non it did not run change detection which is why template was not updated. You could comment that line to check if that was cause of the issue. You are always able to run change detection manually via ChangeDetectorRef.detectChange() docs which should solve you problem
constructor(private cd: ChangeDetectorRef) {}
...
getDetails() {
this.route.params.subscribe(params => {
...
this.getValues().then(() => {
this.isNameAvailable = this.checkNamesAvailability(this.names);
this.cd.detectChanges(); // solution
console.log(this.isNameAvailable);
});
});
}
This stackblitz show this bug and solution. You can read more about change detection here
You could use RxJS timer function with switchMap operator instead of a Promise to trigger something after a specific time.
Try the following
import { Subject, timer } from 'rxjs';
import { takeUntil, switchMap } from 'rxjs/operators';
names= [];
isNameAvailable = false;
closed$ = new Subject();
ngOnInit() {
this.getDetails()
}
getDetails() {
this.route.params.pipe(
switchMap((params: any) => {
this.names.push(params.Names);
return timer(900); // <-- emit once after 900ms and complete
}),
takeUntil(this.closed$) // <-- close subscription when `closed$` emits
).subscribe({
next: _ => {
this.isNameAvailable = this.checkNamesAvailability(this.names);
console.log(this.isNameAvailable);
}
});
}
checkNamesAvailability(names) {
console.log(names);
return names.includes('Sandy');
}
ngOnDestroy() {
this.closed$.next(); // <-- close open subscriptions when component is closed
}

How to refresh tabs in ionic 4

I have a master - detail tab in ionic 4, the master tab gets the list of items that I've created in detail page, but when i create an item and i returned to the tab page, it doesn't refresh automatically.
I've tried using ionDidEnter, ionWillEnter, but nothing works.
This is my code in detail page:
async saveActividad() {
await loading.present().then(async () => {
await this.db.insertItem(item);
this.router.navigateByUrl('/tabs/tab1');
});
}
And this is my code in master page ("tab1")
ionViewWillEnter() {
this.db.getItems()
.then(
(data) => {
if (data !== '') {
this.list = data;
}
}
);
}
You have an TyPo in the event method call.
Instead of:
ionWillEnter() {
// todo
}
Try:
ionViewWillEnter() {
// todo
}
Ionic Page Events explanation
Name - Description
ionViewWillEnter - Fired when the component routing to is about to animate into view.
ionViewDidEnter - Fired when the component routing to has finished animating.
ionViewWillLeave - Fired when the component routing from is about to animate.
ionViewDidLeave - Fired when the component routing to has finished animating.
2) Or if only your tabs are just non-component based html, you could play with the *ngIf directive and invoke a method before returning true:
E.g.:
<section class="master-detail" *ngIf='showIfAvailable();'></section>
async showIfAvailable() {
this.list = await this.db.getItems();
if (list) {
return true;
}
}
Refresh data when function is invoked!
-Best Regards.

JS import - VueJs Router - having trouble refactoring a watch object

This question is specific to vuejs router, however may simply be a misunderstanding of importing js objects and assigning to the window object.
I am watching for url changes on a page which works fine with the watcher code in the component file. I need to use the same watcher code for multiple components so I extracted it to its own file, assigned it to the global scope, and cannot get it to work. Here are the details:
Working code in with the watcher in the component:
watch:{
$route () {
console.log('route changed')
//was it a reset?
console.log( this.$route.query.sort)
if(this.$route.query.sort === undefined){
if(this.$route.meta.reset){
//reset was pressed... actually do nothing here
this.$route.meta['reset'] = false;
}
else{
this.loading = true;
this.searchableTable.removeResultsTable();
this.searchableTable.options.search_query = this.$route.fullPath;
this.searchableTable.updateSearchPage();
}
}
else
{
//sort change just update the table view
}
}
}
So then I extracted the watch to a file routeWatcher.js:
export default {
$route () {
console.log('route changed')
//was it a reset?
console.log(this.$route.query.sort)
if (this.$route.query.sort === undefined) {
if (this.$route.meta.reset) {
//reset was pressed... actually do nothing here
this.$route.meta['reset'] = false;
}
else {
this.loading = true;
this.searchableTable.removeResultsTable();
this.searchableTable.options.search_query = this.$route.fullPath;
this.searchableTable.updateSearchPage();
}
}
else {
//sort change just update the table view
}
}
}
then I import and use, which works fine....
import searchableTableRouteWatcher from '../../controllers/routeWatcher'
...
watch:searchableTableRouteWatcher
again works fine.
Now the problem - I want to avoid the import in multiple files, so I thought I could put it on the window as a global
in my main.js file:
import searchableTableRouteWatcher from './controllers/routeWatcher'
window.searchableTableRouteWatcher = searchableTableRouteWatcher;
Then in my component:
watch:searchableTableRouteWatcher
results in searchableTableRouteWatcher is not defined
watch:window.searchableTableRouteWatcher
results in no errors, but the code is not being called
I have a feeling it has to do with this and there is confusion on $route()
For your purpose there are 'Mixins' in Vue.js: documentation
What you can do:
create a file, say mixins/index.js:
export const routeWatcher = {
watch: {... your watcher code pasted here ... }
};
import into your component:
import { routeWatcher } from 'path/to/mixins/index';
add mixin to your component properties and methods:
<script>
export default {
mixins: [routeWatcher];
data () ...... all your original component's script content
}
Mixin's content will be merged with component's original properties and act if it was hardcoded there.
Addition after your comment:
You can also declare Mixin globally, like this:
above 'new Vue' declaration put this code:
Vue.mixin({
watch: {....}
});
This mixin will appear in every component.

display json data with react and redux

I am attempting to load some local json data with redux and display in react app. But i'm getting the pageId is undefined in the reducer.
Not sure what I am doing wrong here, I think it might be something wrong with how I'm passing the data but im very new to redux so i'm not sure.
Data
const page = [
{"title":"Mollis Condimentum Sem Ridiculus"},
{"title":"Pharetra Tellus Amet Commodo"}
]
export default page;
Action
const getPage = (pageId) => {
const page = { pageId: pageId }
return {
type: 'GET_PAGE_SUCCESS',
payload: page
}
}
export default getPage
Reducer
import getPage from '../actions/actionCreators'
import pageData from './../data/pageData';
const defaultState = pageData
const pageReducer = (state = defaultState, action) => {
if (action.type = 'GET_PAGE_SUCCESS') {
state.page[action.payload.pageId].title = action.payload
}
return state
}
export default PageReducer
Component
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import getpage from '../../actions/actionCreators'
const mapStateToProps = (state, props) => {
const page = state.page[props.pageId]
return { page }
}
class Page extends Component {
componentDidMount () {
this.props.getpage(this.props.pageId)
}
render() {
return (<div><PageContainer pageId={0} /></div>)
}
}
const PageContainer = connect(mapStateToProps, { getpage })(page)
export default Page
I've modified your code into a working JSFiddle for reference: https://jsfiddle.net/qodof048/11/
I tried to keep it as close to your example, but let me explain the changes I made to get it working (also note that JSFiddle does not use the ES6 import syntax).
1) Your PageContainer was not constructed correctly. The last parameter should have been a reference to the Page component (not 'page').
const PageContainer = connect(mapStateToProps, { getPageSimple, getPageAsync })(PageComponent)
2) You used PageContainer in the Page component, but PageContainer is the 'wrapper' around Page. You use PageContainer instead of Page in your render method, so it loads the data (maps state and actions).
ReactDOM.render(
<Provider store={store}>
<div>
<PageContainer pageId="0" async={false} />
<PageContainer pageId="1" async={true} />
</div>
</Provider>,
document.getElementById('root')
);
3) The store was mixed up a bit. If I understood your example correctly you want to load a page into the local store from the pageData array, which simulates a server call maybe. In that case you intialState can't be pageData, but rather is an empty object. Think of it like a local database you're going to fill. The call to your action getPage then gets the page (here from your array) and dispatches it into the store, which will save it there.
const getPageSimple = (pageId) => {
const page = pageDatabase[pageId]; // this call would be to the server
// then you dispatch the page you got into state
return {
type: 'GET_PAGE_SUCCESS',
payload: {
id: pageId,
page: page
}
}
}
4) I've added an async example to the JSFiddle to explain how you would actually fetch the page from the server (since the simple example would not be sufficient). This needs the thunk middleware for redux to work (since you need access to the dispatch method in order to async call it). The setTimeout simulates a long running call.
const getPageAsync = (pageId)=>{
return (dispatch, getState) => {
setTimeout(()=>{
const page = pageDatabase[pageId]; // this call would be to the server, simulating with a setTimeout
console.log("dispatching");
// then you dispatch the page you got into state
dispatch({
type: 'GET_PAGE_SUCCESS',
payload: {
id: pageId,
page: page
}
});
}, 2000);
}
}
The JSFiddle loads 2 containers, one with your simple getPage and one with the async version, which loads the title after 2 seconds.
Hope that helps you along on your react/redux journey.
Hey I see a small mistake in you component, I think. You are doing this.props.pageId, when you are setting page and not pageId on the component's props. So shouldn't it be this.props.getPage(this.props.page.pageId) instead? Could that be it?
Also a small side note, an important tip for using redux is to not mutate state. In you reducer where you are doing state.page[action.payload.pageId].title = action.payload you should probably not set state like that, but instead return a new object called newState which is identical to state, but with the title updated. It is important to treat objects as immutable in Redux. Cheers