Aurelia hook into router before app.js - ecmascript-6

So the aurelia app gets bootstrapped from the main.js
bootstrap(function(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging();
aurelia.start().then(() => aurelia.setRoot('app', document.body));
});
The source code tells me there is a router() method you can call on the FrameworkConfiguration which is what aurelia.use gives you.
But the implementation gives you no hooks, it just includes the framework-templating-router.
The reason I want a hook in, is because I want to do an api call in the activate() of the app.js however, I wish to slide in a Navigation Pipeline middleware before the api call is made.
configureRouter is called after activate() which is obvious. This means I can dynamically inject menu items (api behind authorised walls) to build up my initial screen. If I get a 401 it rejects the activate() promise - which I want - however what would be better is if the pipeline step could Redirect('login').
If I were to put custom login the activate() then I would have two places of redirection, but also it just doesn't fit into the aurelia design very well.
There is an alternative solution which is to defer configuring the router till a child view of the app.js but it doesn't seem as nice.

In your app.js, you can do this:
import {Router} from 'aurelia-router';
#inject(Router)
export class App {
constructor (router) {
this.router = router;
this.router.configure(config => ...);
}
activate () {
...
}
}
Essentially....you don't have to use the configureRouter method. It's just there as a convenience. Using the constructor allows more flexibility in this case.

Related

How to expose a function in svelte that can accept parameters to render?

I'm pretty new to svelte, and for my use case I would like to export the svelte app as a bundle.js which exposes a function let's say startApp(positionInject, appConfiguration) that can accept 2 parameters (positionInject is the app injection position eg: .app, appConfiguration is the initial configuration of the app to start), based on those parameters svelte app start renders.
I am wondering, this is possible in svelte?
Appreciate any help.
Every Svelte component takes a target element and props as constructor parameters. You can wrap the construction in a function:
import App from './App.svelte';
export function startApp(selector, props) {
const target = document.querySelector(selector)
return new App({
target,
props
})
}
And you can call it like this:
import {startApp} from "./bundle.js"
startApp(".my-app", {config: ...})

How controllers and functions communicate between two separate files using .emit and how to tell controller hierarchy in AngularJS?

This is my first post on stack overflow so I am really green and really new with AngularJS and ASP.Net and having a lot of problems with $rootscope.$emit. From what I have read online $rootscopes are parent scopes so all values exposed there are visible to all controllers and templates and scopes are functions inside of controllers. It seems like you can "emit" up through the controller hierarchy a call to another controller by using $rootscope.$emit("Name of $rootscope.$on function name") the $rootscope.$on listens for that call and then does whatever is in its function. The thing I am having trouble with is when I do my
$rootscope.$emit("LoadPrintDetailsModal", {});
it never seems to reach
$rootscope.$on("LoadPrintDetailsModal", function(event,args) {}.
So the question is am I misunderstanding how $emit or how controller hierarchy works or is there a problem in my code?
I have already tried using emit and I hit the debugger in indexController.js file after a call from a button in my Index.cshtml file but then when I make the
$rootScope.$emit("LoadPrintDetailsModal", {});
it does not get picked up by my printableController.js file where
$rootScope.$emit("LoadPrintDetailsModal", function (event, args) {});
// (Index.cshtml) Button in Index.cshtml file that calls "LoadPrintModal" //function in indexController
<button type="button" data-toggle="modal" data-target="#dvPrintModal"
ng-click="LoadPrintModal()">
Print
</button>
// (indexController.js)scope.LoadPrintModal in indexController.js that tries
// to emit "LoadPrintDetails" to $rootscope.%on("LoadPrintDetailsModal",
// function (event, args) in printableçontroller.js
$scope.LoadPrintModal = function () {
debugger;
$rootScope.$emit("LoadPrintDetailsModal", {});
};
// (printableController.js) file where rootScope.on is located and is supposed to pick up the emit
app.controller('PrintableController', function ($scope, $rootScope) {
$rootScope.$on("LoadPrintDetailsModal", function (event, args) {
debugger;
$scope.printModal();
});
$scope.printModal = function () {
console.log("Hello World");
};
)};
The expected result should be a console log of hello world and we should hit the debugger in printableController.js file
Use $rootScope.$broadcast:
$rootScope.$broadcast("LoadPrintDetailsModal", {});
The $broadcast method dispatches events down the scope heirarchy.
The $emit method dispatches events up the heirarchy.
For more information, see
AngularJS Developer Guide - Scope Event Propagation
To capture broadcast events, use $scope.$on:
app.controller('PrintableController', function ($scope, $rootScope) {
̶$̶r̶o̶o̶t̶S̶c̶o̶p̶e̶.̶$̶o̶n̶(̶"̶L̶o̶a̶d̶P̶r̶i̶n̶t̶D̶e̶t̶a̶i̶l̶s̶M̶o̶d̶a̶l̶"̶,̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶e̶v̶e̶n̶t̶,̶ ̶a̶r̶g̶s̶)̶ ̶{̶
$scope.$on("LoadPrintDetailsModal", function (event, args) {
debugger;
$scope.printModal();
});
$scope.printModal = function () {
console.log("Hello World");
};
)};
From the Docs:
Only use .$broadcast(), .$emit() and .$on() for atomic events
Events that are relevant globally across the entire app (such as a user authenticating or the app closing). If you want events specific to modules, services or widgets you should consider Services, Directive Controllers, or 3rd Party Libs
Injecting services and calling methods directly is also useful for direct communication
Directives are able to directly communicate
For more information, seed
AngularJS Wiki - Best Practices
It's hard to know what is happening without:
seeing the hierarchy of the components. Is the emitting component is down in the hierarchy from the catching component. $emit is sending messages up. $browdcast is sending messages down.
Seeing how you inject $rootscope.
Regarding 2. $rootscope injection gives you the main $scope of the application. Doing $emit from it won't gives us anything as there are no $scopes that are above the $rootScope.
My guess you want to inject $scope which represent the specific scope in the hierarchy for that controller/component. Then $emiting will propagate upward to the catching controller/component properly.

Prefetch resources for async routes

Is there a way to prefetch or preload async routes? I'm exploring how to do this right now with RR2/3. The basic idea is I code split on every route but I'd like to be able to cache bundles for connected pages in a service worker before visiting that page. So what I'd like to do is have a custom <Link> that every time it's rendered, it tries to cache the resources of the page it's linked to. This would make page transitions considerably faster. What I don't know is if there's a way to emulate navigating to a route so that the resources will be fetched. Is there an API for this or some sort of tricky way to do this someone can think of?
This is what I came up. It's a component that wraps the React Router Link component and in componentDidMount (so only runs on the client not the server) check if in production (no need to run this during development) and if this is a browser that doesn't support Service Workers (this check is specific to my use case). Then manually match against the location and call any async getComponent functions.
import React from 'react'
import Link from 'react-router/lib/Link'
class GatsbyLink extends React.Component {
componentDidMount () {
// Only enable prefetching of Link resources in production and for browsers that
// don't support service workers *cough* Safari/IE *cough*.
if (process.env.NODE_ENV === 'production' && !('serviceWorker' in navigator)) {
const routes = require('my-routes')
const { createMemoryHistory } = require('history')
const matchRoutes = require('react-router/lib/matchRoutes')
const getComponents = require('react-router/lib/getComponents')
const createLocation = createMemoryHistory().createLocation
if (typeof routes !== 'undefined') {
matchRoutes([routes], createLocation(this.props.to), (error, nextState) => {
getComponents(nextState, () => console.log('loaded bundle(s) for ' + this.props.to))
})
}
}
}
render () {
return <Link {...this.props} />
}
}
module.exports = GatsbyLink
You could just do a require.ensure... section in a timeout when the Link is mounted. That should require the code split and load it up async. The timeout will ensure it get's loaded in a separate file.
I would recommend using RR4 for code splitting as I found in RR3 the async required routes get re-included and re-rendered if a child route changes. In my case, I had the componentWillMount of my routes being fired for any child route changes. e.g. Navigating from /agent/step-1 to /agent/step-2 will cause the Component for /agent to be unmounted and re-mounted.

Webpack: ES6 modules, code splitting, and bundle-loader

TL;DR: Could you please explain when bundle-loader is needed for code splitting using Webpack?
When I started migrating a Backbone-based app from Require.js to Webpack, I remember that this kind of require statement in the router:
someMatchedRoute: function () {
require(['path-to-file'], function(module) {
// doing something with the loaded module
module();
});
}
would put the required code in the same bundle as the rest of the code, and in order to generate a separate file that would be required dynamically when switching to a particular route, I needed to use bundle-loader, like so:
// a function executed when the user’s profile route is matched
someMatchedRoute: function () {
require('bundle!path-to-file')(function(module) {
// doing something with the loaded module
module();
});
}
Now, when I am migrating my codebase to ES6 modules and using the require.ensure syntax as described in Webpack documentation:
someMatchedRoute: function () {
require.ensure(['path-to-file'], function(require) {
var loadedModule = require('path-to-file');
// doing something with the loaded module
loadedModule();
});
}
I am unsure whether I need bundle-loader at all to in order to generate multiple chunks and load them dynamically. And if I do, in which require call does it go — in the require.ensure or in the require in the callback? Or maybe both? It's all so confusing.

Polymer + page.js flash notifications with paper-toast

I'm building a mid sized app with Polymer and used the Polymer Starter Kit to kick things off which uses page.js for routing.
I want to implement flash message functionality using the paper-toast element.
In other technologies/frameworks this is implemented by checking to see if a property exists when the route is changed.. if it does, it shoes the relevant flash/toast message.
How... with Polymer & Page.js is it possible to replicate this type of functionality? Page.js doesn't seem to have any events for changed routes.
The only way I can think is to create a proxy function for the page('/route') function that I have to call every time I want to go to a new page which then calls the actual page function. Is there a better way?
I've implemented this like follows for the time being... seems to be ok but if anyone can suggest improvements let me know.
In routing.html
window.addEventListener('WebComponentsReady', function() {
// Assign page to another global object
LC.page = page;
// Define all routes through this new object
LC.page('/login', function () {
app.route = 'login';
app.scrollPageToTop();
});
....
//implement remaining routes
// page proxy... to intercept calls
page = function(path) {
// dispatch event
document.dispatchEvent(new Event('LC.pageChange', {path: path}));
// call the real page
LC.page(path);
};
});
Then where you want to listen.. in my case in a lc-paper-toast element added to the index.html file of the app I can now listen to when the page is changed...
ready: function() {
document.addEventListener('LC.pageChange', function(e){
console.log('page change' , e);
}, false);
}
Only thing to be aware of is that all page changes must be called with page('/route') otherwise it won't go through the proxy.