angular routing something weird happening - html

I am still learning angularjs so maybe there's something stupid I am not understanding but I have a really strange behaviour when using routing.
In my application I use the following code to define my routes:
var app = angular.module('app', []);
app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.
when('/pneumatici/:chunka', {}).
when('/pneumatici/:chunka/:chunkb', {});
$locationProvider.html5Mode(true);
}]);
And in a controller I manage them this way:
app.controller('appCtrl', ['$scope', '$route', '$routeParams', '$location', function ($scope, $route, $routeParams, $location) {
$scope.$on('$routeChangeSuccess', function (current,previous) {
if (!($location.path().indexOf('/pneumatici') === -1)) {
$scope.chunka = $route.current.params.chunka; $scope.chunkb = $route.current.params.chunkb;
/** do my stuff with chunka and chunkb **/
} else {
window.location.href = $location.path();
}
});
I have no ngView, no template, nothing.
It works like a charm.
Please note the line where I actually force a page load in case the url is not intended to be managed by the controller appCtrl.
I was forced to do that because once I define my route to catch '$routeChangeSuccess' all links in the page when clicked are catched by angular and no page load occurs even if the link doesn't have the format defined with 'when'.
I would have like to do it with 'otherwise' but I could not understand how to, if doable.
Now the problem.
In the page of course I have links like just '/privacy.html', if I click them the page load is correctly triggered and I do see '/privacy.html' but unfortunately once there if I click the back button I can see the url of the browser changing to (let's say) /pneumatici/foo/bar but no page load is triggered.
Please note in the privacy.html page I have no angular routing defined, there's no .config no .when; there's an anagular app defined, with a controller, but no injection of '$routeProvider' anywhere, no definition of any route.
What is happening? What I am doing wrong?
Thanks for any help!
Update.
I found a viable solution adding:
angular.element("a").prop("target", "_self");
Angular routing is ignored for all 'a' elements with 'target' set to "_self", didn't know that.
Still if I look at this strategy as a whole doesn't sound very elegant to me and I would love to improve it. What I don't like is since I am defining the route in .config I should be able to tell angular to skip any url which do not match the format/path I defined there.
But I don't know if that is doable or not, does anyone know out there?

By turning on html5mode your app should be acting like it should intercept everything on the site by default (from '/'.)
From that perspective, it seems like $location.path() should work in your explicit override, but it isn't really correct ($location.url() would be) and the browser already has the correct URL, so maybe you can't force a reload with location.href = location.href in your specific browser.
Rather than going down that path, I would do the following to make it DRY:
If you add a base href:
<base href="/pneumatici/"></base>
and replace /pneumatici/ with / in your when clause(s):
$routeProvider.
when('/:chunka', {}).
when('/:chunka/:chunkb', {});
then you should just need this:
$scope.$on('$routeChangeSuccess', function (current,previous) {
$scope.chunka = $route.current.params.chunka;
$scope.chunkb = $route.current.params.chunkb;
/** do my stuff with chunka and chunkb **/
});

I think you should let Angular manage all your routes like this:
var app = angular.module('app', []).config(function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
$routeProvider
.when('/',
{
controller: 'HomeController',
templateUrl: '/partials/home.html'
})
.when('/about',
{
controller: 'AboutController',
templateUrl: '/partials/about.html'
})
.when('/privacy',
{
controller: 'PrivacyController',
templateUrl: '/partials/privacy.html'
})
.when('/404',
{
controller: 'NotFoundController',
templateUrl: '/partials/404.html',
})
.otherwise({
redirectTo: '/404'
});
});
Notice the otherwise above. That tells angular to load the 404 page when a route is not recognized.

Related

I need to escape! Angular $sce not handling links to audio files (Strict Contextual Escaping)

I have Angular and $sce working on my project for displaying HTML special characters, and for a video player's links to video files in my database. But I can't get $sce to connect the HTML audio player to audio files on the same database.
This HTML works:
<audio controls ng-src="https://mydatabase.com/aa6df923">
This is the project HTML:
<audio controls ng-src="{{audioSource}}">
This doesn't work:
$scope.audioSource = "https://mydatabase.com/aa6df923";
This also doesn't work:
app.controller('MyController', function($scope, $sce) {
$scope.audioSource = $sce.trustAsResourceUrl("https://mydatabase.com/aa6df923");
});
This doesn't work either:
app.controller('MyController', function($scope, $sce) {
$scope.audioSource = $sce.trustAsResourceUrl("https://mydatabase.com/aa6df923");
$scope.$apply();
});
Not this one either:
$scope.audioSource = "../audio/myFile.mp3";
And, finally, this filter works to escape HTML special characters but don't work to link the audio files:
<audio controls ng-src="{{audioSource | trustAsHtml}}">
app.filter('trustAsHtml', [$sce', function($sce) {
return function(html) {
return $sce.trustAsHtml(html);
};
}]);
What am I missing?
You can create a new filter called trustAsResourceUrl that will work the same as your trustAsHtml example.
Create a trustAsResourceUrl filter:
app.filter('trustAsResourceUrl', ['$sce', function($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
}]);
note that there is a typo in your example - a ( between return and function
Use the filter in your template:
<audio controls ng-src="{{ audioSource | trustAsResourceUrl }}">
Keep in mind this will trust every URL you pass to the filter.
If you just want to whitelist a domain you can do this in your app.config().
angular.module('app')
.config(['$sceDelegateProvider', function($sceDelegateProvider) {
// whitelist resource URLs
$sceDelegateProvider.resourceUrlWhitelist([
'self',
'https://mydatabase.com/**'
]);
}]);
Otherwise the code in your earlier examples should work, assuming the domains match, etc. If these solutions don't fix your issue you it would be helpful to post the full error you are seeing in the console.
I've started to figure it out. $scope.audioSource is inside a function, which puts it on a new $scope. I.e., {{audioSource}} and $scope.audioSource are on different scopes. I'll work on returning values out of functions and onto the controller's $scope.

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.

HTML default URL param on page load

Task:
When I load page http://127.0.0.1:53132/pages/login.html I want it by default become http://127.0.0.1:53132/pages/login.html#/existinguser. Maybe someone can tell me how to make that?
I using html, angularjs.
Tried:<meta http-equiv="refresh" content="0; url=#/existinguser" /> but it keeps refreshing page infinitely.
ROUTE CONFIG
loginApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/existinguser', {
templateUrl: '../../pages/loginForms/existingUserForm.html',
controller: 'existingUserCtrlr'
})
.when('/newuser', {
templateUrl: '../../pages/loginForms/newUserForm.html',
controller: 'newUserCtrlr'
});
}]);
For default path use otherwise in routing config:
$routeProvider
.when('/existinguser', {
templateUrl: '../../pages/loginForms/existingUserForm.html',
controller: 'existingUserCtrlr'
})
.when('/newuser', {
templateUrl: '../../pages/loginForms/newUserForm.html',
controller: 'newUserCtrlr'
}).otherwise({
redirectTo: '/existinguser'
});
This means that if none of the defined routes exist in url when page loads, the path in the redirectTo will load
You need to define the default route in the router with the 'otherwise' option
When you first navigate to your site you probably load the index.html. that needs to redirect to the #/whatever route you want and the router then takes over from there.
Technically with the # you are still on the index.html page and you whole app is a single page, with the router routing requests on the client, not the server, but loading the proper template in the Dom to show the page you want, loading it from the server if needed (if not cached previously)
Try this doc
https://docs.angularjs.org/tutorial/step_07

Angular-Translate: Translation does not show up on random browser refreshes

I have a separate language json file for each partial/controller. To avoid loading all the json files at once, I have added the addPart statement in the controller instead of the module config:
$translatePartialLoader.addPart('editName');
When I browse to the partial, I see that the json file is requested from the server only when needed. But when I keep refreshing the partial by clicking the function key F5, at random times, the json file is not requested from the server and the text displayed on the view is not translated. Not sure what I can do to fix this. Any help is greatly appreciated. Here is the code:
angular.module('pp')
.controller('informationList', [
'$scope', '$rootScope', '$location', '$translatePartialLoader', '$translate',
function($scope, $rootScope, $location, $translatePartialLoader, $translate) {
$translatePartialLoader.addPart('informationList');
$translate.refresh();
}
]);
Your issue sounds similar to mine.
This (called from app config) works:
angular.module('myApp').config(function ($translateProvider, $translatePartialLoaderProvider) {
$translateProvider.useLoader('$translatePartialLoader', {
'urlTemplate': '{part}-{lang}.json'
});
$translateProvider.preferredLanguage('EN');
$translatePartialLoaderProvider.addPart('headline');
$translatePartialLoaderProvider.addPart('languages');
});
This (called from controller) does not:
angular.module('myApp').controller('Ctrl', ['$scope', '$translate', '$translatePartialLoader', function ($scope, $translate, $translatePartialLoader) {
$translatePartialLoader.addPart('headline');
$translatePartialLoader.addPart('languages');
$translate.refresh();
}]);
Here is a plunker to demonstrate the problem.
http://plnkr.co/edit/sZC2XST8BMZcMCYbgtxt?p=preview
Could you just add a
$translateProvider.use('EN');
to the config - section just right below the "preferredLanguage('EN');" - line?
This should solve your problem.
It is in in fact currently needed to define that additional line - even though it might sound a bit like "duplication" :-).

Html5 mode Angularjs Express URL rewrite returns index page for ALL requests

I've been using similar questions to try and find the solution to the problem I'm having. I understand that in order to use html5Mode with angularjs I need to tell the server how to handle a direct visit to a page.
I have the issue where clicking on the link within the app renders the page fine but a direct visit does not display offers.
E.g.
http://localhost:3001/offers/television/
should call in routes.js
app.get('/offers', offers.all);
and it does when the link
televisions
is clicked
When I directly visit it however it looks like my angular service is returning the index page as resources...!
//Offers service used for offers REST endpoint
angular.module('mean.offers').factory("Offers", ['$resource','$routeParams',function($resource,$routeParams) {
return $resource('/offers/:offerId',
{offerId: '#_id'},
{
search: {'method': 'GET', params: {}, isArray:true}
});
}]);
I've also got base(href="/") in my index.jade head
angular config.js
//Setting up route
window.app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/offers/:type/',{
controller: 'OffersController',
templateUrl: 'views/offers/list.html'
}).
when('/', {
templateUrl: 'views/index2.html'
}).
otherwise({
redirectTo: '/'
});
}
]);
//Setting HTML5 Location Mode
window.app.config(['$locationProvider',
function($locationProvider) {
$locationProvider.hashPrefix("!");
$locationProvider.html5Mode(true)
}
]);
express routes.js
//Offer Routes
var offers = require('../app/controllers/offers');
app.get('/offers', offers.all);
app.get('/offers/:offerId', offers.show);
//Home route
var index = require('../app/controllers/index');
app.get('/', index.render);
express.js
app.configure(function() {
// app.use('/', express.static(__dirname + '/'));
//cookieParser should be above session
app.use(express.cookieParser());
//bodyParser should be above methodOverride
app.use(express.bodyParser());
app.use(express.methodOverride());
//routes should be at the last
app.use(app.router);
app.get('/*', function(req, res) {
res.render('index');
});
...
Why is it not returning offers even though it should hit the /offers route in express routes.js? Or am I doing something odd?
Thanks!
As you mentioned in the comments of the question, "app.get('/offers', offers.all); will handle /offers/:offerId". This means that going directly to http://localhost:3001/offers/television/ will be handled by your offers.all function (not shown in post), not the '/*' handler that returns the index.
To fix this you have options.
Check the route to see if it is an AJAX request or not. If it is,
return your data, if it is not, return the index.
Put your API behind a path (like /api) then all of your API requests will go to
/api/offers/:offId to get data. This frees up /offers/:offerId
to be handled by '/*', returning the index
Edit:
I see the confusion, app.router (Node.js / Express.js - How does app.router work?). In a nutshell, app.use(app.router); tells express which order to run the routes as a whole. The order you provide the routes in matter after that point. From your code (again, not showing all of it) you only really define 1 route, app.get('/*', function(req, res) { res.render('index'); });. You have the separate route files, but no where in what you have posted do you includes those scripts. They are not automatically included by default.