In an angular component I'm generating an image from a service http call, which then I want to display on the site. However it's taking longer for the image to generate than it takes the site to load.
Thus I'm forced to refresh a few extra times to see/display the actual image when it finally loads.
How can i make ngOnit wait for everything to be generated and loaded before displaying the page?
this.someService.generateImage().subscribe(x => {
console.log('Image is now in folder')}
I want the page to be displayed after this call.
Any hints for this?
You can do like this:
Markup:
<div *ngIf="!isLoading">
// do not show till loading
</div>
Component:
isLoading = true;
this.someService.generateImage().subscribe((x) => {
console.log('Image is now in folder')
this.isLoading = false;
})
On your ngOnInit use :
ngOnInit() {
this.someService.generateImage().subscribe(x => {
//load page content functions.
console.log('Image is now in folder')
});
}
This is a work around since ngOnInit() on itself doesn't wait for async calls
Why stop the ngOnInit execution instead let it load all the dependency just don't show it,
The hack you can apply is hiding the contents of the complete page by a blocking loader with a loader service and show the content of the page when the image is generated. Something like this.
ngOnInit() {
loaderService.show();
this.someService.generateImage().subscribe(x => {
loaderService.hide();
console.log('Image is now in folder')
}
[Extra dependencies stuff .....]
}
You can use ngAfterViewInit() It get executed after dom loaded fully
Related
I am trying to toggle a view between grid and list view mode on my frontend HTML page. I am able to do this fine with dom and HTML classes manipulation by toggling "display: none" between two containers. However, when I go to the next product page(through pagination) or when I reload the page, the default view is the one that appears and not the one that was last toggled. Is there a way to persist the view in case a page reload or product pagination changes? thank you.
here is the dom code that achieves this :
viewList.addEventListener('click', function() {
this.classList.add('view__active');
viewGrid.classList.remove('view__active');
gridItem.classList.add('hidden');
listItem.classList.remove('hidden');
});
viewGrid.addEventListener('click', function() {
this.classList.add('view__active');
viewList.classList.remove('view__active');
gridItem.classList.remove('hidden');
listItem.classList.add('hidden');
});
So far I found that I have to use localStorage to achieve this. but is there a better way to do this?
Essentially what is happening is when you request something from the server, the server responds with an HTML document, and whichever scripts associated with that document is run, So whatever JS executed in the first request is not in context when the second request(paginate or reload) is made.
So you need a way to persist information across these page loads, For that, you have 3 options.
Use sessionStorage.
Use localStorage
Use Cookies.
Of the 3 above the easiest would be to use either option 1 or 2.
Replying to your comment,
Also, If I am using localStorage, What am I using to store the view state?
I'm not quite clear as to what you mean by "What you are using to store the state" If your question is about where your data is stored, you need not worry about it as this is handled by the browser. If your question is about "How" to store it you can go through the MDN docs attached in option 1 or 2. This is simply storing a key-value pair as shown in the docs
localStorage.setItem('preferedView', 'grid'); You can add this to your on click handlers as follows,
viewList.addEventListener('click', function() {
this.classList.add('view__active');
viewGrid.classList.remove('view__active');
gridItem.classList.add('hidden');
listItem.classList.remove('hidden');
localStorage.setItem('preferedView', 'grid');
});
viewGrid.addEventListener('click', function() {
this.classList.add('view__active');
viewList.classList.remove('view__active');
gridItem.classList.remove('hidden');
listItem.classList.add('hidden');
localStorage.setItem('preferedView', 'list');
});
Then when loading a new page at the top of your script you can get the users preferedView(if existing) via const preferedView = localStorage.getItem('preferedView');
Here is a complete example from MDN
In order for anyone to find an answer for a similar task, thanks to #Umendra insight, I was able to solve this by using this :
function viewToggeler(viewBtn1, viewBtn2, view1, view2, viewStord) {
viewBtn2.classList.add('view__active');
viewBtn1.classList.remove('view__active');
view1.classList.add('hidden');
view2.classList.remove('hidden');
sessionStorage.setItem('preferedView', viewStord);
}
viewList.addEventListener('click', () => {
viewToggeler(viewGrid, viewList, gridItem, listItem, 'list');
});
viewGrid.addEventListener('click', () => {
viewToggeler(viewList, viewGrid, listItem, gridItem, 'grid');
});
if (sessionStorage.getItem('preferedView') === 'grid') {
viewToggeler(viewList, viewGrid, listItem, gridItem, 'grid');
} else if (sessionStorage.getItem('preferedView') === 'list') {
viewToggeler(viewGrid, viewList, gridItem, listItem, 'list');
}
I ended up using sessionStorage over localStorage because it empties itself on window/tab closing which might be the most desirable result. localStorage persists even after exiting the browser and opening it back.
Also, at any point someone wants to empty the sessionStorage on exit, I used :
window.addEventListener('onbeforeunload', () => {
sessionStorage.removeItem('preferedView');
});
I develop a custom html page with information about installed certificates on the local machine. The certificate's information I get by crypto provider api, then I filter returned certificates with some restrictions (Issuer, CommonName, etc). This is the work of my function loadCertificates. I show results on button click. But loadCertificates takes some seconds and I want to show preloader before loadCertificates and hide after:
$("#select__cert-btn").click(function () {
showPreloader();
var certificates = loadCertificates(restrictions);
hidePreloader();
showCerificates(certificates);
});
Functions showPreloader and hidePreloader only add/remove div with gif background to the container with certificates info. But when I click on the button my page seems frozen and only after some seconds show results (without appearing my preloader). But in debug mode, before run loadCertificates the preloader is added to html, but it's not visible.
Early I have never the same problem, but it seems like loadCertificates block main thread, but if I'm right why showPreloader not work correclty?
How to solve my problem?
I would try to use a promise so that the loadCertificates runs async without locking the main thread.
Try this:
$("#select__cert-btn").click(function () {
showPreloader();
var certificates = new Promise(function(resolve, reject) {
loadCertificates(restrictions);
resolve();
});
certificates.then(function(result) {
hidePreloader();
showCerificates(certificates);
});
});
if your loadCertificates function call an endpoint via ajax then you can simply add a html region that will be hide/shown with a gif image (loading) :
<!-- Will be called on every ajax call to show the spinner -->
<div class="row" id="ajaxLoading" style="display:none">
<div class="col-md-4 offset-4">
<img src="~/Images/loading.gif" />
</div>
</div>
then add in your scipt file :
var ajaxLoading = $('#ajaxLoading');
//add a spinner to every ajax call
$(document).ajaxStart(function () {
ajaxLoading.show();
});
$(document).ajaxStop(function () {
ajaxLoading.hide();
});
I have a project developed in Angular 6+, when user comes to website, first he sees logo and loading bar underneath it.
I have a problem switching to ngx-loading-bar insted of pace.js
Right now I am using Pace (the last example a fixed width line)
https://github.hubspot.com/pace/docs/welcome/
integrated into the index.html of the root project.
I want to put ngx-loading-bar instead of pace to do same job.
ngx-loading-bar is already implemented and working when adding <ngx-loading-bar></ngx-loading-bar> in some of the components but not in the index.html.
I want to put same style same width loading bar as on example link bellow (4th bullet example, similar to pace)
https://aitboudad.github.io/ngx-loading-bar/
so on the load, users sees the loading bar how it loads and on load, it goes on the next component as project example bellow.
Here is the example of project
www.wowlectures.com/pitchdeck
Not sure why you want it to work in index.html, do it in app.component.
You could create a loading service. A simple way is this:
#Injectable({providedIn: 'root'})
export class LoadingService {
private _loading = true;
get isLoading() {
return this._loading;
}
set isLoading(v: boolean) {
this._loading = v;
}
}
Then in app.component.ts:
export class AppComponent {
constructor(public loading: LoadingService) {}
}
And app.component.html:
<any-loading-component *ngIf="loading.isLoading"></any-loading-component>
<router-outlet></router-outlet>
A cleaner way is to use subjects/observables in the service and subscribe to changes where you want to show the loading-bar and dispatch from anywhere you want it to start loading.
<app-root>
<ngx-loading-bar></ngx-loading-bar>
</app-root>
hey you can add this in your index.html
When a user changes the theme, I use mainWindow.webContents.send to change a class in the DOM. I also save it in the store, under the key theme.
mainWindow.webContents.send('theme:change', theme);
store.set('theme', theme);
Then in renderer.js:
ipcRenderer.on('theme:change', (event, theme) => {
document.querySelector('body').className = `${theme}`;
});
This successfully changes the theme and saves it in the store. However, now I want that theme to load up when starting the application rather than going back to the default. To do this, in app.on('ready') I am doing this:
mainWindow.webContents.send('theme:change', store.get('theme'));
However, nothing is happening. It's like it isn't being sent. Where am I going wrong? Essentially what needs to be done is for the class in body to be changed when the application loads to the one in the store.
Figured it out. I had to put:
mainWindow.webContents.once('dom-ready', () => {
mainWindow.webContents.send('theme:change', store.get('theme'));
})
I was trying mainWindow.on('dom-ready') which is why it wasn't working.
I'm building my first lavavel website from scratch and I've run into a behavioral issue with a few routes.
Here is the relevant code for my routes file:
Route::get('work', 'PageController#work');
Route::get('work/{item}', 'PageController#workitem');
And here are the relevant methods:
public function work() {
return view('pages.work');
}
public function workitem($item) {
$v = 'work.'.$item;
if(view()->exists($v)) {
return view($v);
} else {
return view('errors.noitem');
}
}
And here is the relevant part of my view:
#extends('layout')
#section('content')
...
<div class="workflex">
<a class="workitem" href="/work/test"></a>
<a class="workitem" href="/work/test2"></a>
</div>
<div id="loadContent" class="loadContent">
#yield('insert')
</div>
...
#stop
It is worth mentioning that I intend to load the individual workitem pages with PJAX. I have views that the PJAX loads into the the "insert" section based on the URL:
$(document).pjax('a.workitem', '#loadContent');
The user loads the initial work page at the /work subdirectory, and clicks a button to load /work/item pages with PJAX. As the routes suggest, I also want the user to be able to enter a workitem into the URL and be directed to the work page already loaded with that item. This whole system behaves as intended... until I added the following jquery to work.blade.php:
$(document).ready(function() {
$('#loadContent').load("/work/init", function() {
myFade('#loadContent > *', 1); //ignore this function, it's an animation irrelevant to my problem
});
});
This is here as an attempt to load a initial message inside the PJAX loading div #loadContent to tell the user to select a workitem. However, a side effect of this is that now whenever I browser to a /work/item directly (PJAX still loads the pages correctly) the document triggers this jquery and the message overrides the page content.
I was brainstorming ways to allow the work() method in my controller to trigger something that loads this script or passes just the work/init view into the "insert" section.
What do you think would be the best way to solve this? Your answers are greatly appreciated.
I was able to answer my own question. I forgot about the route optional parameters. I changed/added these things:
Route::get('work/{item?}', 'PageController#work');
and in my controller:
public function work($item = 'init') {
$v = 'work.'.$item;
if(view()->exists($v)) {
return view($v);
} else {
return view('errors.noitem');
}
}
Works perfectly now!