ui.router not working well in custom directive - angularjs

I am working on custom directives in AngularJS and getting help from Mark Zamoyta's tutorials from PluralSight.
M using UIRouter in angular which is not working well in custom direcives while ngRoute is working well.Here is position of ui-view
<ng-transclude></ng-transclude>
<div ui-view></div>
In Controller i've this code to use routes/states getting from custom directive.
$scope.$on('ps-menu-item-selected-event', function (evt, data) {
$scope.routeString = data.route;
//$location.path(data.route);
$state.go(data.route);
checkWidth();
broadcastMenuState();
});
Now,I f i use ngroute then it is showing partial/template at right place but if i use ui router it goes out of ui-view ang show partials/templaes but not in between
<div ui-view></div>
i have thse searches who lead me to downgrading ui router's version but no success.
1.ui-view doesn't work when used inside angularjs custom directives
2.https://github.com/angular-ui/ui-router/issues/774
Any Help?????

When you use $location.path(url), you pass in something like /home/item into the url, but when you use $state.go(state), you pass in the state name like home.item. Make sure you pass the right thing.

Related

Angular 1.5 component $router binding

I'm trying to switch a 1.5x project over to components and use the new component-router. I'm having an issue with how to programmatically access the $router in a couple of components that aren't sitting inside of a directive. Basically I have header and sidebar components which need to be able to do $router.navigvate, but using bindings: {$router: "<"} gives me an undefined $router.
I think I might just need to restructure the app a little bit, but I'm not sure how to go about it.
Currently in my Index.html I have ng-app defined on the body, and then the main app module inside of that (<app></app>).
My main app component has a template with basically my "masterpage".
So app.html has a <header> component, <sidebar> component, and then <ng-outlet> for the main content. With UI-Router I just used the $state service in the header/sidebar controllers to find the active state or navigate to a new state.
With component-router I can't figure out how to get the $router into the header/sidebar controllers.
Any ideas?
use $rootRouter in the controller
function controller($rootRouter){
$rootRouter.navigate(["someComponent"])
or $rootRouter.navigateByUrl("/url")
}

Preserve traditional anchor behavior with ng-include

I am not building a single-page application, but rather a "traditional" site that uses AngularJS in places. I've hit the following problem (using 1.3.0-beta.6):
Standard, working anchor links:
Link text
... [page content]
<a id="foo"></a>
<h1>Headline</h1>
[more content]
That works fine. Now I introduce a template partial somewhere:
<script type="text/ng-template" id="test-include.html">
<p>This text is in a separate partial and inlcuded via ng-include.</p>
</script>
which is invoked via:
<div ng-include="'test-include.html'"></div>
The partial is included properly, but the anchor link no longer works. Clicking on "Link text" now changes the displayed URL to /#/foo rather than /#foo and the page position does not change.
My understanding is that using ng-include implicitly tells Angular that I want to use the routes system and overrides the browser's native anchor link behavior. I've seen recommendations to work around this by changing my html anchor links to #/#foo, but I can't do that for other reasons.
I don't intend to use the routes system - I just want to use ng-include without it messing with browser behavior. Is this possible?
The reason is that angular overrides the behavior of standard HTML tags which include <a> also. I'm not sure when this change happened because angular v1.0.1 works fine with this.
You should replace the href attribute with ngClick as:
<a ng-click="scroll()">Link text</a>
And in a controller so:
function MyCtrl($scope, $location, $anchorScroll) {
$scope.scroll = function() {
$location.hash('foo');
$anchorScroll();
};
};
Demo: http://jsfiddle.net/HB7LU/3261/show/
Or simply use double hash as:
<a href='##foo'>Link text</a>
Demo: http://jsfiddle.net/HB7LU/3262/show/
Update: I did not know that you want no modification in HREF. But you can still achieve the desired result by overriding the existing a directive as:
myApp.directive('a', function() {
return {
restrict: 'E',
link: function(scope, element) {
element.attr('href', '#' + element.attr('href'));
}
};
});
Demo: http://jsfiddle.net/HB7LU/3263/
My understanding is that using ng-include implicitly tells Angular
that I want to use the routes system and overrides the browser's
native anchor link behavior. I've seen recommendations to work around
this by changing my html anchor links to #/#foo, but I can't do that
for other reasons.
Routing system is defined in a separate module ngRoute, so if you did not injected it on your own - and I am pretty sure you did not - it is not accessible at all.
The issue is somehow different here.
ng-include depends on: $http, $templateCache, $anchorScroll, $animate, $sce. So make use of ng-include initiate all these services.
The most natural candidate to investigate would be $anchorScroll. The code of $anchorScroll does not seem to do any harm, but the service depends on $window, $location, $rootScope. The line 616 of $location says:
baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
So basically the base href is set to '', if it was no set before.
Now look HERE - from BalusC answer :
As to using named anchors like , with the tag
you're basically declaring all relative links relative to it,
including named anchors. None of the relative links are relative to
the current request URI anymore (as would happen without the
tag).
How to mitigate the issue?
I do not have much time today, so cannot test it myself, but what I would try to check as the first option is to hook up to '$locationChangeStart' event and if the new url is of #xxxxxx type just prevent the default behaviour and scroll with $anchorScroll native methods instead.
Update
I think this code should do the work:
$scope.$on("$locationChangeStart", function (event, next, current) {
var el, elId;
if (next.indexOf("#")>-1) {
elId = next.split("#")[1];
el = document.getElementById(elId);
if(el){
// el.scrollIntoView(); do not think we need it
window.location.hash = "#" + elId;
event.preventDefault();
}
}
});
This is the best solution, and works in recent versions of Angular:
Turn off URL manipulation in AngularJS
A lot late to the party but I found that adding a simple target="_self" fixes it.
Link
Rather than applying the angular application to the entire page, you can isolate the application to just the places you want to perform an ng-include. This will allow links outside the scope of the application to retain their normal functionality, while allowing links within the application to be handled as desired.
See this plunkr:
http://plnkr.co/edit/hOB7ixRM39YZEhaz0tfr?p=preview
The plunkr shows a link outside the app that functions as normal, and a link within the app that is handled using an overriding a directive to restore normal functionality. HTML5 mode is enabled to retain 'standard' URLs (rather than 'hashbang' [without the bang!] URLs).
You could equally run the whole of the page within the app, but I thought it would be worth demonstrating how to isolate angular to certain parts of the page in any case.

Angular 1.1.5 url is duplicated when using ngInclude

I'm using angular 1.1.5 with ngInclude in my template. Whenever I load the page I get a duplicate path after the hashbang: http://localhost/home#/home, http://localhost/account#/account, etc. This happens when there's ngInclude directive in the page (I think this also happens with ngView). I'm not using any routing with this app, and it's a very simple setup overall.
Using $locationProvider.html5Mode(true) in the module configuration seems to resolve this, but I don't want to use that as it doesn't really fit with this application's design.
This doesn't seem to happen in angular 1.2.0-RC.2, but I don't want to migrate just yet. Any known workarounds? thanks.
Use a function as the value:
app.controller("foo", function($scope) {
$scope.url = function() {
return "/bar";
}
});
<div ng-controller="foo">
<ng-include src="url()"></ng-include>
</div>

AngularJS - Multiple ng-view in single template

I am building a dynamic web app by using AngularJS. Is it possible to have multiple ng-view on a single template?
You can have just one ng-view.
You can change its content in several ways: ng-include, ng-switch or mapping different controllers and templates through the routeProvider.
UI-Router is a project that can help: https://github.com/angular-ui/ui-router
One of it's features is Multiple Named Views
UI-Router has many features and i recommend you using it if you're working on an advanced app.
Check documentation of Multiple Named Views here.
I believe you can accomplish it by just having single ng-view. In the main template you can have ng-include sections for sub views, then in the main controller define model properties for each sub template. So that they will bind automatically to ng-include sections. This is same as having multiple ng-view
You can check the example given in ng-include documentation
in the example when you change the template from dropdown list it changes the content. Here assume you have one main ng-view and instead of manually selecting sub content by selecting drop down, you do it as when main view is loaded.
Using regular ng-view module you cannot have more than one dynamic template.
However, this project enables you to do so (look for ui-router).
It is possible to have multiple or nested views. But not by ng-view.
The primary routing module in angular does not support multiple views.
But you can use ui-router. This is a third party module which you can get via Github, angular-ui/ui-router, https://github.com/angular-ui/ui-router . Also a new version of ngRouter (ngNewRouter) currently, is being developed. It is not stable at the moment.
So I provide you a simple start up example with ui-router.
Using it you can name views and specify which templates and controllers should be used for rendering them. Using $stateProvider you should specify how view placeholders should be rendered for specific state.
<body ng-app="main">
<script type="text/javascript">
angular.module('main', ['ui.router'])
.config(['$locationProvider', '$stateProvider', function ($locationProvider, $stateProvider) {
$stateProvider
.state('home', {
url: '/',
views: {
'header': {
templateUrl: '/app/header.html'
},
'content': {
templateUrl: '/app/content.html'
}
}
});
}]);
</script>
<a ui-sref="home">home</a>
<div ui-view="header">header</div>
<div ui-view="content">content</div>
<div ui-view="bottom">footer</div>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js">
</body>
You need referencing angularjs, and angular-ui.router for this sample.
$ bower install angular-ui-router
You cant have multiple ng-view. Below is my use case where I solved my requirement.
I wanted to have tabbed behavior in my model dialog. I was facing issue as click on tabs having hyperlink which will invoke router links. I solved this using button and css for tabs. When user clicks on tab, it actually will not call any hyperlink which will always invoke the ng-router. When user click on tab it will call a method, where I dynamcilly load html. Below is the function on click of tab
self.submit = function(form) {
$templateRequest('resources/items/employee/test_template.html').then(function(template){
var compiledeHTML = $compile(template)($scope);
$("#d").replaceWith(compiledeHTML);
});
User $templateRequest. In test_template.html page add your html content. This html content will be bind to your controller.

I'm implementing on-the-fly dashboards in AngularJS

Can I implement something like:
$scope.showDashboard = function () {
$scope.dashboardPath = "/Widgets/Weather/View.htm";
$scope.widgetController = 30;
require(['/Widgets/Weather/Controller.js'], function (w) {
whatShouldIputHere = w;
});
};
<div ng-include src="dashboardPath" ng-controller="whatShouldIputHere?"></div>
Is it possible to assign a controller to ng-include dynamically?
There could be many widgets on the dashboard
There is a project in development that implements dashboard functionality with AngularJS.
Features:
Adding/removing widgets
Widgets drag and drop
Any directive can be a widget
Running Demo http://nickholub.github.io/angular-dashboard-app
Demo source code https://github.com/nickholub/angular-dashboard-app
Dashboard directive itself https://github.com/nickholub/angular-ui-dashboard
We created an angularjs based dashboard in the open source hawtio project. You can noodle the code here if you like:
https://github.com/hawtio/hawtio/tree/master/hawtio-web/src/main/webapp/app/dashboard
For each widget on the dashboard we compile the partial directly with a child scope
https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/app/dashboard/js/dashboard.ts#L142
Though we had to patch angularjs to allow us to use custom injection on child scopes. e.g. so that we can use a different implementation of $location for each child widget (so it thinks its on its own real URL etc). Hopefully when custom injectors are supported we can move to that.
Instead of using dynamic controllers why not use a single controller(the one which has the showDashboard method). Adding dynamic controller with ng-include will result in nested controllers which is illegal i guess. And instead of using ng-include as an attribute use it as an element.
<ng-include src="dashboardPath"></ng-include>

Resources