I've learning this new tool since some days ago and know I'm beggining to have my own doubts.
I have an index.html, which holds almost all my app like so:
<html>
<head>
.
.
.
<body>
<div ng-include="'header.html'"></div>
<div ui-view></div>
.
<!-- Loads all the scripts and other stuff-->
</body>
Ok, in the website I'm building, I have some sections that share the header, that's why I include it. Nonetheless, there is another section where is completely different from the others, hence, I don't need to include the header.
Now, the question is: How can I route to this completely new section ? Because the index loads the other views in the below the header. All I can think about right now is creating another index.html-like page, loading all the scripts and everything again. I think there should be a more elegant solution in Angular.
I'm using angular-ui-router for the routing.
Can you please give me a hand? Thanks
Use nested states, put this in your app's state configuration.
$stateProvider.
$state('stateWithHeader', {
template: '<header></header><div ui-view></div>',
controller: 'HeaderStateController'
}
.$state('stateWithHeader.subState', {
template: '<div>Content!</div>',
controller: 'HaderSubStateController'
}
.$state('stateWithoutHeader', {
template: '<div>Yeah, no header!</div>',
controller: 'HeaderStateController'
};
Make sure to read the docs, they're super informative and clear on most subjects.
What #Claies said above will absolutely work. Here's an example from my own site at http://PaperQuik.com.
I have multiple routes which correspond to different templates. Each one just does the following to get the same menu header at the top of the page:
<div ng-include="'views/menu.html'"></div>
If I needed a different top I could use a different include. You can see the source to my various templates here: https://github.com/JohnMunsch/PaperQuik/tree/master/app/views
Note: My example is just using the old ngRouter (not the new one which is expected for AngularJS 1.4) and thus it is way less sophisticated than what you can do with either the new ngRouter or the AngularUI Router you're using. Still, you can see how easy it is even with that super simple router.
Related
I've worked with many languages and environments (predominately iOS & C#) and have always managed to avoid working with scripting languages. That avoidance streak has come to an abrupt end: as a huge angularjs project was thrown in my lap - now I'm scrambling to understand this very strange world. Some features are really cool, other techniques have me thoroughly baffled. I've spent weeks reading tutorials, studying examples and I still cannot solve a relatively simple problem regarding best practices and structure of the code.
This is what I need to do: I have a form, where the user will input data (for argument's sake, its two fields of number type.) I need to have a banner at the top of the page with the sum of the two input fields - that by itself is relatively easy - but the problem for me, is repeating this banner on subsequent pages.
Home page will contain links to:
page 1
page 2
The link to page 2 will not be available until the user inputs data on page 1, forcing the user to visit page 1, first. The banner element needs to be a separate file. Page 2 is a passive display of the data, Page 1 is only page that can actively edit the data.
page 1: would look like this --
banner.html (sum of fields A & field B)
input field A
input field B
page 2:
banner.html (sum of field A & field B)
Lorem Ipsum ....
What's the best way to achieve this task?
You can have an index page with the banner on top, and partials using the same controller. The value of the banner will be a controller variable.
To use partials, inside the index page, you'll need to include the ngRoute module, and the script tag linking to it.
You'll have a div like this.
<div ng-view=""></div>
You'll have a partialRoutes.js file looking something like this.
myApp.config(function($routeProvider){
$routeProvider
.when('/',{
templateUrl: './partials/things.html'
})
.when('/stuff',{
templateUrl: './partials/stuff.html'
})
.when('/otherstuff',{
templateUrl: './partials/otherstuff.html'
})
.otherwise({
redirectTo: '/',
})
});
When you include ngRoute it will look something like this.
var myApp = angular.module('myApp', ['ngRoute']);
Here are the docs for ngRoute. Hope I helped.
https://docs.angularjs.org/api/ngRoute
Personally, I would have a service, lets call it userData. Your inputController would then write the details of the inputs to the userData service.
Your bannerController would then be notified of changes to the data in the userData service (via $watch or $broadcast)
This way when you switch pages the bannerController should not change and will still display this information
Notes:
This relies on you using some kind of AngularJS routing technique such as NGroute or UI Router. If a hard page navigation is made then the userData will have to be stored server side.
It would probably be better for the banner to stay outside any ui-view so that it is unaffected by navigation, but if it is then as the userData service will still be alive and holding the correct data when it is recreated it will have access to the same data
If both pages have same controller, then $scope can be used to achieve this. If pages have different controller, $rootScope can be used to share variables.
I am very new to angular and working on some code that I wanted to upgrade the angular version from 1.2.3 to 1.3.15 (which I have also never done before). When I did, the navigation links on my index page stopped working; rather it seems like the router.js falls through to my $routeProvider.otherwise case and redirects to /home (you can see the refresh in my jumbotron). However, I also notice that when I click on the links, my url goes from localhost:8888/home to localhost:8888/home# or localhost:8888/home#home or localhost:8888/home#info, but the page routes don't work (the home page gets refreshed instead) - like the route is just appended to /home and it doesn't know what to do.
When I remove the deep linking ( hash / pound / # ) from the links in index.html, the code appears to work again, but I don't really understand why. It's highly likely I'm misunderstanding something in the breaking changes from 1.2 to 1.3, but the documentation made it seem like using # is still supported in 1.3.
By "upgrading" I replaced my angular.js, angular-resource.js, and angular-route.js in my project with their newer versions. I am using Apache karaf, and tested in both Chrome and Firefox with the same results.
Shortened code below:
Here is the index.html code that works in 1.2.3 and breaks in 1.3.15 (I used both # and #home to test if there would be a difference):
<div class="navbar navbar-inverse navbar-fixed-top">
...
My Project<small></small>
...
<div class="collapse navbar-collapse navHeaderCollapse" data-ng-controller="NavController">
<ul class="nav navbar-nav navbar-right">
<li class="{{navData['Home'].css}}">Home</li>
<li class="{{navData['Info'].css}}">Info</li>
</ul>
</div>
</div>
</div>
My router.js looks like:
angular.module("app").config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/home', {
templateUrl: "home.html",
controller: "HomeController",
isPublic: false
});
$routeProvider.when('/info', {
templateUrl: "info.html",
controller: "InfoController",
isPublic: false
});
$routeProvider.otherwise({ redirectTo: '/home' });
});
With 1.3.15, when I replace the hash / pound / # signs in index.html, with "/" for Home and "info" instead of the "#info", everything seems to work again.
I also tried upgrading potential dependencies to the following:
ui-bootstrap-tpls-0.13.0.js (was 0.6.0)
jquery-2.1.4.js (was 2.0.3)
I am using:
bootstrap.js (using 3.0.0)
I also have some additional libraries but didn't know if they are relevant to this. Let me know if I should add them to the list.
I attempted to simulate what I am seeing in plunker here: Angularjs v1.3.15 test # redirect
But the links appear to be working with the exception of when you click a link with just "#" as the href, the page template isn't loaded at all. So I don't know if the issue is related or completely different.
A few suggestions I've looked into (but maybe missed something):
I did see that people are upgrading ui-router, but I'm not currently using it; should I be? (Though plunker seems to be working with angular-route.js)
html5 is not playing nice in all arenas, but it appears configured in my code?
fixing the server to allow #, which I think is already done since the code used to work correctly
Thanks in advance for the help! If you could point me in the right direction that would also be appreciated!
The hash has a specific meaning in the HTML specification. It targets an element on a page. If you are on the page localhost:8888/home and click on the link localhost:8888/home#info the browser would jump to the element with the id info, if there was one. Consequently nothing happens if the element doesn't exist.
Angular intercepts clicks and url changes and allow you to change routes instead. To avoid any confusion (or unintentional behavior) Angular has two conventions. The first is using a prefix. It's optional and the one suggested is !. That's why this mode is also called the Hashbang mode, links to routes would start with #!.
The second, and more important one, is that routes start with /. So it's href="#/" and href="#/info". And this works no matter what version of Angular you are using. Of course, this fixes your plunker.
If you want to use hashes then don't activate the HTML5 mode.
One remark about your last point: The server doesn't care about #, since it only concerns the client.
All I am trying to do is include an anchor tag inside the html of a partial that links to an external site. Were this standard html, the code would simply be:
google
As simple as this is, I cannot seem to find a working solution for getting past angular intercepting the route (or perhaps replacing my anchor with the https://docs.angularjs.org/api/ng/directive/a directive unintentionally?).
I have scoured SO and the rest of the web and seen a myriad of solutions for dealing with: links within the same domain, routing within the SPA, routing within a page (ala $anchorScroll) but none of these are my issue exactly.
I suspect it may having something to do with using $sce but I am an Angular n00b and not really sure how to properly use that service. I tried the following in my view controller:
$scope.trustUrl = function(url) {
return $sce.trustAsResourceUrl(url);
}
with the corresponding:
<a ng-href="{{ trustUrl(item) }}">Click me!</a>
(as described here: Binding external URL in angularjs template)
but that did not seem to do the trick (I ended up with just href="{{" in the rendered page).
Using a plain vanilla anchor link like this:
google
also failed to do the trick (even though some online advised that standard href would cause a complete page reload in angular: AngularJS - How can I do a redirect with a full page load?).
I also tried adding the target=_self" attribute but that seemed to have no effect either.
Do I need to write a custom directive as described here?
Conditionally add target="_blank" to links with Angular JS
This all seems way too complicated for such a simple action and I feel like I am missing something obvious in my n00bishness, at least I hope so because this process is feeling very onerous just to link to another url.
Thanks in advance for any solutions, advice, refs or direction.
It turns out that I did in fact have all anchor links in the page bound to an event listener and being overridden. Since that code was fundamental to the way the page worked I did not want to mess with it. Instead I bypassed it by using ng-click to call the new url as follows:
HTML:
<a class="navLinkHcp" href="{{hcpurl}}" title="Habitat Conservation Plan" target="_blank" ng-click="linkModelFunc(hcpurl)">Habitat Conservation Plan</a>
Controller:
$scope.hcpurl = 'http://eahcp.org/index.php/about_eahcp/covered_species';
$scope.linkModelFunc = function (url){
console.log('link model function');
$window.open(url);
}
And voila! Good to go.
Thanks again to KevinB for cluing me in that this was probably the issue.
I'm trying to redirect to an external page from my AngularJS file if the user enter a special url, for instance /test. I have gotten this to work in multiple different ways but all the different ways show a "flash" of the design from index.html. I would like it to go direct without rendering any html at all!
Here is a fiddle of one of the examples, but it is not the best place to test since I cant redirect from jsiffle.net :-)
$routeProvider.when("/test", {
resolve: {
controller: "Redirect"
}
});
Also had one example where I just used a controller and a empty template in the routing, but it gave me the same result.
Any ideas?
If you know the URL(routing) then use,
$location.path('the_URL');
So not 100% of my site is "powered by AngularJS" some of it is just simple static HTML like a landing page or content oriented stuff, which is simple HTML for obvious reasons.
The only way I can seem to get a link to navigate normally is like this:
$routeProvider
.when('/plans', {templateUrl: '<%= asset_path('ng/views/start.html') %>'})
# Catch all
.otherwise({ redirectTo: (p,loc) -> window.location = loc })
It feels like the catch all should be simpler like I could do .otherwise(false) and it would just navigate normally. Same goes for `.when('/something'/, false) but I don't see anything in the docs that suggests this is possible.
Does anyone know of a better way to do this?
Edit 1:
One solution I've found is to use target='_self' in the link.
The other is apparently to set the "base url" of the application as outlined in the docs. Then any links outside of that base should navigate normally. However that doesn't seem to work as outlined and the example doesn't match what the documentation is suggesting either.
just creating a link to it external file
if you are using hashbang urls (e.g. #/plans) then you should be all set, if you are using html5 history api ($locationProvider.html5(true)) then you need to namespace your app (set base[href] properly) and put the content outside of that namespace.
relevant code:
https://github.com/angular/angular.js/blob/4df45b20d460239a0f5001fb0dd59f95e2d0e80d/src/ng/location.js#L560
Another solution is to use target="_self" on that a element. Again this should be an issue only when html5 (history pushState) is being used.