Durandal delayed composition on landing page? - durandal

I've been using Durandal for a landing page of sorts, and using it to populate the main content of a page (#applicationHost, red area below). It works, but page rendering speed is an issue (requirejs, ajax calls, composition, etc)
Since we have the content data already, we were considering rendering the page content server-side.
However we would still like to use Durandal on this page to allow hash-routing to other views, trigger Durandal dialogs, and to data-bind some observables that can be loaded asynchronously. (areas in green below)
Problem is I don't want to replace #applicationHost content (red above) immediately when starting Durandal on this landing page. For hash-routing to other views, I would like to replace or hide it.

Not sure exactly what you're asking, but it sounds like this might solve at least part of the problem.
You can use 'promises' to enforce a minimum delay between the splash screen loading and your app doing whatever startup it needs to do. Assuming a common setup where your Durandal main.js loads shell.js on startup, return a combined promise from the shell.js 'activate' callback. I recommend using the Q library for promises (Q + Durandal docs).
shell.js would contain something like the following. The logic below causes the splash screen to be displayed for at least 3 seconds. Longer if initializeAppPromise takes longer than 3 seconds:
in shell.js...
activate = function(){
var initializeAppPromise = router.map(....)..etc...activate();
var minimumDelayPromise = Q.delay(3000); //give splash animation/whatever time to display
return Q.all([initializeAppPromise, minimumDelayPromise ])
.spread(function(routerActivationResponse){
return routerActivationResponse;
});
}

Came up with a decent solution for this, hope it helps others:
https://github.com/bestguy/durandal-delayed-composition

Related

asyncData hook when hard refreshing in Nuxt

I just realized that the asyncData hook is not called when hard refreshing the page. But I have important data to load to show on that page. And I want to make sure that they are always available, even when the user hard refreshes the page.
asyncData from the documentation
the promise returned by the asyncData hook is resolved during route transition
In that case, the best way is to use the fetch() hook and display a loader while you do finish your calls thanks to the $fetchState.pending helper.
Actually, I do think that fetch() is better in many ways.
Quick article on the subject: https://nuxtjs.org/blog/understanding-how-fetch-works-in-nuxt-2-12/
The one on the bottom of the page (Sergey's) is cool with some practical example of a nice implementation too.
You could also use this somewhat hacky solution in a layout to see if the initial location (the one you are when you hard refresh) is the one you want to be. Basically, if you land on a specific page (hard refresh or following a new window page for example) but want to have some custom behavior.
beforeCreate() {
if (!['some-other-page'].includes(this.$router.history._startLocation)) {
this.$router.replace({ name: 'index' }).catch(() => {})
}
},
Still, this one infinite loops if used in a middleware (or I made a mistake) and it's less clean than a fetch() hook.

The Vue Component is not fully rendered

I am trying to use one of the Material Design Lite templates inside my Vue.js application.
What happens is, when I am routed(using this.$router.push('/templateX') to the next page, the component is not fully rendered(I can see only the header).
What is really interesting, when I take a look at the source section inside the browser console, I can see that the template is loaded but not fully rendered.
Once I reload the page, then the whole template is rendered and everything is shown as expected.
I think the problem is in the component life cycle but I am not sure what shall I do exactly. Any thoughts?

Masonry, Lazy load and ACF Gallery Field

I'm using the ACF gallery field to add images into a custom post type. The problem is that in the case of one post I've added around 80 images which means that they all have to load before Masonry is triggered. I thought I'd use lazy load to load the images in as you scroll down the page but that requires for you to know the image dimensions.
I found this https://github.com/okadots/masonry-wp-lazy-load but it turns out that it isn't very secure.
Anybody have any other ideas?
You can use something like imagesLoaded (which is made by the creator of Masonry) to make sure all images are loaded before triggering Masonry.
imagesLoaded in Masonry documentation: http://masonry.desandro.com/appendix.html#imagesloaded
You can use the imagesLoaded plugin, found here: http://imagesloaded.desandro.com/ then each time an image gets loaded you can refresh the layout of the grid, it will look like this:
// init Masonry
var $grid = $('.grid').masonry({
// options...
});
// layout Masonry after each image loads
$grid.imagesLoaded().progress( function() {
$grid.masonry('layout');
});
each time you add more items to the grid, probably via AJAX, you'll need to execute the lines where you layout masonry
if you are having a hard time with this you can use a plugin ready to use, like this one: https://codecanyon.net/item/media-boxes-portfolio-responsive-grid/5683020 with this plugin you can have lazy load, you only specify the URLS of your images and the plugin will do the rest, you can configure how many images you want to load on each set

Win8 JS App: How can one prevent backward navigation? Can't set WinJS.Navigation.canGoBack

Fairly new to developing for Windows 8, I'm working on an app that has a rather flat model. I have looked and looked, but can't seem to find a clear answer on how to set a WinJS page to prevent backward navigation. I have tried digging into the API, but it doesn't say anything on the matter.
The code I'm attempting to use is
WinJS.Navigation.canGoBack = false;
No luck, it keeps complaining about the property being read only, however, there are no setter methods to change it.
Thanks ahead of time,
~Sean
canGoBack does only have a getter (defined in base.js), and it reflects the absence or presence of the backstack; namely nav.history.backstack.
The appearance of the button itself is controlled by the disabled attribute on the associated button DOM object, which in turn is part of a CSS selector controlling visibility. So if you do tinker with the display of the Back button yourself be aware that the navigation plumbing is doing the same.
Setting the backstack explicitly is possible; there's a sample the Navigation and Navigation History Sample that includes restoring a history as well as preventing navigation using beforenavigate, with the following code:
// in ready
WinJS.Navigation.addEventListener("beforenavigate", this.beforenavigate);
//
beforenavigate: function (eventObject) {
// This function gives you a chance to veto navigation. This demonstrates that capability
if (this.shouldPreventNavigation) {
WinJS.log && WinJS.log("Navigation to " + eventObject.detail.location + " was prevented", "sample", "status");
eventObject.preventDefault();
}
},
You can't change canGoBack, but you can disable the button to hide it and free the history stack.
// disabling and hiding backbutton
document.querySelector(".win-backbutton").disabled = true;
// freeing navigation stack
WinJS.Navigation.history.backStack = [];
This will prevent going backward and still allow going forward.
So lots of searching and attempting different methods of disabling the Back Button, finally found a decent solution. It has been adapted from another stackoverflow question.
Original algorithm: How to Get Element By Class in JavaScript?
MY SOLUTION
At the beginning of a fragment page, right as the page definition starts declaring the ready: function, I used an adapted version of the above algorithm and used the resulting element selection to set the disabled attribute.
// Retrieve Generated Back Button
var elems = document.getElementsByTagName('*'), i;
for (i in elems)
{
if((" "+elems[i].className+" ").indexOf("win-backbutton") > -1)
{
var d = elems[i];
}
}
// Disable the back button
d.setAttribute("disabled", "disabled");
The code gets all elements from the page's DOM and filters it for the generated back button. When the proper element is found, it is assigned to a variable and from there we can set the disabled property.
I couldn't find a lot of documentation on working around the default navigation in a WinJS Navigation app, so here are some methods that failed (for reference purposes):
Getting the element by class and setting | May have failed from doing it wrong, as I have little experience with HTML and javascript.
Using the above method, but setting the attribute within the for loop breaks the app and causes it to freeze for unknown reasons.
Setting the attribute in the default.js before the navigation is finished. | The javascript calls would fail to recognize either methods called or DOM elements, presumably due to initialization state of the page.
There were a few others, but I think there must be a better way to go about retrieving the element after a page loads. If anyone can enlighten me, I would be most grateful.
~Sean R.

Lazy Load - refresh / update when combined with javascript filtering

I am now trying to implement lazyload onto my website.
I have successfully got lazy load working on pages that have a static gallery.
The main portfolio of the website has a large list of images that can be filtered using the javascript library Isotope.
The lazy load works fine when filtering is not in used, however, if the page loads and I don't scroll, but filtering is used, the items which are brought into view don't resolve. I found that occasional images worked, but most don't.
Any suggestions on how to fix this?
Presumably i need to be able to do something that will re-trigger lazy load to refresh or recheck itself?
Here is the gallery I am trying to get working, where you can see the issues I am having: http://www.imageworkshop.com/lazyload-portfolio/
Anyone able to help?
call this code on filtered item is clicked: $(window).trigger('scroll');
I found this answer from acarabott - https://stackoverflow.com/a/13919010/735369
I have implemented this and this has worked.
The only issue is that the refresh doesn't happen until a scroll action takes place.
If you want to use isotope's sorting/filtering functions, you will need to set the failure_limit of lazyload and trigger the event with isotope's onLayout callback.
jQuery(document).ready(function($) {
var $win = $(window),
$con = $('#container'),
$imgs = $("img.lazy");
$con.isotope({
onLayout: function() {
$win.trigger("scroll");
}
});
$imgs.lazyload({
failure_limit: Math.max($imgs.length - 1, 0)
});
Explanation
According to the docs ( http://www.appelsiini.net/projects/lazyload )
After scrolling page Lazy Load loops though unloaded images. In loop it checks if image has become visible. By default loop is stopped when first image below the fold (not visible) is found. This is based on following assumption. Order of images on page is same as order of images in HTML code. With some layouts assumption this might be wrong.
With an isotope sorted/filtered list, the page order is certainly different from the HTML so we need to adjust our failure_limit.
As you can see we store the jQuery object so that we can use its length-1 as our failure_limit. If you're curious as to why it is length-1, it's because of the following check in lazyload's update method.
if (++counter > settings.failure_limit) {
return false;
}
Lazy load on other events
If you are not triggering your lazyloads on scroll, you will need to swap the "scroll" trigger for whichever event you are using.
Demo
http://jsfiddle.net/arthurc/ZnEhn/