angular: updating a view without page reload - angularjs

I have a rootScope json array that's viewed is several controllers, and gets updated in yet another controller. The json array contains urls that get updated. The view controllers show updated urls about half the time, but if I reload the page, I do get updated views 100% of the time.
I have tried using $scope.$apply() and $timeout, but they made no difference.
Could someone please tell me what angular tools are out there for this? I'm hoping there is a simple approach to it.

Going off of my earlier comment:
Index
<!doctype html>
<html ng-app="myapp">
<head>
<!--Head stuff-->
</head>
<body>
<div ng-view=""></div>
<!-- Scripts, other stuff -->
</body>
</html>
Main Script
'use strict';
angular
.module('myapp', [
//...
'ngRoute',
//...
])
.config(function (..., $routeProvider, ...) {
$routeProvider
.when('/404', {
templateurl: '404.html',
controller: 'ErrorCtrl',
controllerAs: 'errorCtrl',
title: 'You are lost'
})
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeCtrl',
controllerAs: 'homeCtrl',
title: 'Home'
})
.when('/contact', {
templateUrl: 'views/contact.html',
controller: 'ContactCtrl',
controllerAs: 'contactCtrl',
title: 'Contact Us'
})
.otherwise({
redirectTo: '/404'
});
//...
})
.run (function (...) {
//...
});
Usage
Contact Us
You'd be taking all of the base template code that's common to your pages and be including that on index. Basically, the stuff that doesn't change will always be there. Otherwise, take it off of the main page and put it into a template file with its own controller. Alternatively, have some shared controllers and just use the views as templates, then shovel all of the functionality into directives. I actually prefer the latter method, but the former is shown above.
What's noteworthy about this solution is that the page is only actually loaded once. Since you stay on the index whenever you navigate to a different view, you only need to grab the HTML for the new template from your server and inject it into the view (which ngRoute takes care of). I believe that by default you'll have a # in your URL, so you'll probably want to enable HTML5 mode.$locationProvider into your config function and then add this line:
$locationProvider.html5Mode ({ enabled: true });
You also need to add a base to the head element of your index file:
<base href="/" />
Homework: Routes tutorial, HTML5 mode
If you use Grunt, you might also want to look into ngTemplates. It can really boost performance.

Related

Error 404 when serving files in angularjs and node app

I have
<base href="/!#/">
at the top of my index.html file. When I go to URL http://localhost:5000/ everything works fine, it instantly add #!/ so the URL is http://localhost:5000/#!/ and page display as expected.
At the server side I have following code which should allow me to use my files
app.use(express.static(path.join(__dirname, 'public')));
Structure of my files is something like:
bookApp(folder)
server.js
public(folder)
index.html
app.js(ngRoute)
views(folder)
css(folder)
controllers(folder)
and my AngularJS routing is:
(function () {
'use strict';
angular
.module('app', [
'ngRoute'
])
.config(config);
function config ($routeProvider) {
$routeProvider
.when('/', {
controller: 'PostsCtrl',
templateUrl: 'views/posts.html'
})
.when('/register', {
controller: 'registerCtrl',
templateUrl: 'views/register.html'
})
.when('/login', {
controller: 'loginCtrl',
templateUrl: 'views/login.html'
})
.otherwise('/');
}
})();
The very first page (views/posts.html) load as expected but when I click
<li>Sign in</li>
the URL is http://localhost:5000/login not as like I thought http://localhost:5000/!#/login.
and it display:
Cannot GET /login
when I manually change URL to http://localhost:5000/#!/login it works fine.
How to fix this behavior?
The only solution I see is to get rid of <base> tag and in every link manually in href directive add !# before slash.
It looks like you are forgetting the ng-view directive: <div ng-view></div> which is the container for the content that is provided by your routing. Place this above your script if you have everything contained in one file.
You can also try:
<ng-view></ng-view>
<div class="ng-view"></div>
Is there any particular reason you are still using Angular 1? I know this isn't technically answering your question, but I would highly recommend that you start using the latest Angular. You can still keep legacy code but it will make a lot of what you are doing a lot cleaner and clear.

Argument 'mainController' is not a function, got undefined 1.4

There are a ton of examples of using the newer angular directives like ng-blur, ng-focus, form validation, etc. They all work great in a single page, or in plinkr, jsfiddle, etc. with the exception of the people who try to define the function on the global namespace, that mistake is WELL documented.
However, I was having a different problem.
I was using an example from Scotch.io. This one works great...until you introduce it into an SPA that is using angular-route :(
After many hours of fighting with the error 'Argument 'mainController' is not a function, got undefined', I found the answer in a comment from Hajder Rabiee.Thanks Hadjer, Love you man!
Hajder left this comment and in it, he says:
If you're using routes (high probability) and your config has a reference to a controller in a module that's not declared as dependency then initialisation might fail too.
E.g assuming you've configured ngRoute for your app, like
angular.module('yourModule',['ngRoute'])
.config(function($routeProvider, $httpProvider) { ... });
Be careful in the block that declares the routes,
.when('/resourcePath', {
templateUrl: 'resource.html',
controller: 'secondModuleController' //lives in secondModule
});
Declare secondModule as a dependency after 'ngRoute' should resolve the issue. I know I had this problem.
Even with this help it took me a minute to get it working, so I thought I would share my sample code here to help the next poor bastard that gets stuck on this.
First, in the place where i declare my routes:
var app = angular.module('sporkApp', ['ngRoute','validationApp']);
app.config(function ($routeProvider) {
$routeProvider
.when('/home',
{
controller: 'HomeController',
templateUrl: 'home/home.template.html'
})
.when('/tags',
{
controller: 'TagsController',
templateUrl: 'tags/tags.template.html'
})
.when('/test',
{
controller: 'mainController',
templateUrl: 'test/test.template.html'
})
.otherwise({ redirectTo: '/home' });
});
Then, you need to add your controller code somewhere, where it will get loaded in your shell page:
// create angular app
var validationApp = angular.module('validationApp', []);
// create angular controller
validationApp.controller('mainController', function($scope) {
// function to submit the form after all validation has occurred
$scope.submitForm = function() {
// check to make sure the form is completely valid
if ($scope.userForm.$valid) {
alert('our form is amazing');
}
};
});
Finally, you need to add the corresponding ng-app and ng-controller to some page element that wraps the controls you want to validate. I put the following inside of a div tag:
<div ng-app="validationApp" ng-controller="mainController">

Redirect to a new template in angular js

I am new to angularjs, so please consider my mistakes.
The scenario is, I have an index.html page and login.html page, index and login will have different layout thus different header footer and all.
All other pages expect login will share same layout as index.html
Now, how can I navigate to login.html using anuglar ui router.
myApp.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state('home', {
url: '/',
templateUrl: 'app/views/site/home.html',
controller: 'homeCtrl'
}).state('login', {
url: '/login',
templateUrl: 'app/views/site/login.html'
})
});
This does not work as it loads the content of login into index keeping header and footer same of index. I know the state is supposed to work that way.
Now, is there any way I can just call a completely new view using ui.router.
I really appreciate your help.
Thanks
You could probably set up multiple named views (https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views).
This would allow you to make the header and footer into separate views that you can swap in and out. I don't think there is a way to completely swap out an entire page, though.
<body>
<header ui-view="header"></header>
<main ui-view="content"></main>
<footer ui-view="footer"></footer>
</body>
.state('login', {
views: {
'header': { ... templates and/or controllers ... },
'content': { ... templates and/or controllers ... },
'footer': { ... templates and/or controllers ... },
}
})
I achieve this by making my entire layout into templates. Essentially, my index.html is nothing more than this:
<html ng-app="appName" ng-strict-di>
<head>
<title></title>
</head>
<body>
<div class="ng-cloak" ng-cloak ui-view></div>
</body>
</html>
Then I use abstract states to create template zones. For instance, my auth states:
$stateProvider
.state('auth', {
abstract: true,
url: '/auth',
template: '<div ui-view></div>'
})
.state('auth.login', {
url: '/login',
templateUrl: 'auth/login.html',
controller: [ loginController],
controllerAs: 'vm'
})
.state('auth.logout', {
url: '/logout',
resolve: {
logout: [ 'api', function (api) {
return api.getLogout().$promise;
}]
},
controller: [ logoutController],
controllerAs: 'vm'
});
This causes the auth/login route to render directly into the main ui-view where it can have it's own unique layout. Similarly, I may have an abstract core state that sets a common scope and template for the core parts of my app, which all share a common template structure.
If there are re-used elements that touch both the core and auth sections, then I use ng-include to bring in those individual partials.

ionic/angularjs app construction

When making an ionic app what is the best method of creating different pages of information?
Right now I have separate html documents for each page and a button pointing to each html document; however, I feel like angular/ionic provides a better way of doing so that I missed. For example, the app I am making has a main page with buttons for 5 places. Each button loads a completely new html document with info about the place labeled on the button.
If it is too much to explain, a link answering what I am asking is fine
Thanks
What you want are angular templates. You can write a template once, and then pass in information from the controller to take the place of the angular bindings. You have one master template, that changes the angular bindings depending on which information you pass it in the controller.
For example, you could have your application load in partial templates for each location, and display them all on your main page without having to hit a new html document. Check out the example in the Angular Tutorial.
And the Live Demo
You can do it by uiROUTER, For example: angular.module('ionicApp', ['ionic']) .config(function ($stateProvider, $urlRouterProvider) { $stateProvider .state('menu', { abstract: 'true', templateUrl: 'templates/menu.html', controller: 'MenuCtrl' }) / ... / .state('menu.work', { url: '/work', views: { menuContent: { templateUrl: 'templates/work.html', controller: 'WorkCtrl' } } }); $urlRouterProvider.otherwise('/work'); });

Update ng-class on HTML tag when routing

I'm writing a Chrome extension using AngularJS. The UI is served via a browser action popup and as the content changes I sometimes need to change the size of the popup. The only way I've been able to do this is to change the CSS sizing attributes on the HTML and BODY tags via conditional updates of the class, i.e.
<!DOCTYPE html>
<html lang="en" ng-app="oApp" ng-controller="QuestionsCtrl" ng-class="{true:'expand'}[doExpand]">
<head>
...
</head>
<body ng-class="{true:'expand'}[doExpand]">
...
I have an ng-click on a control that sets 'doExpand' and this works nicely. However, I'm updating the app now to use routing to display multiple views. In doing that I'm removing the inline controller declaration...
<!DOCTYPE html>
<html lang="en" ng-app="oApp" ng-class="{true:'expand'}[doExpand]">
...
... and defining it in the routing config:
var oApp = angular.module('oApp', ['ngRoute', 'oControllers']);
oApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: '/partials/login.html',
controller: 'LoginCtrl'
}).
when('/board', {
templateUrl: 'partials/board.html',
controller: 'QuestionsCtrl'
}).
when('/board/:questionId', {
templateUrl: 'partials/question-detail.html',
controller: 'QuestionDetailCtrl'
}).
otherwise({
redirectTo: '/login'
});
}
]);
The routing is working but the problem is that the HTML tag is now outside the scope of the controller since that's now on the views themselves. I can stick the BODY tag in the views I suppose, but can't do the same for the HTML tag since the JS includes need to be in the head, etc. (and other reasons)
Can someone offer me advice on how to handle this scenario? Thank you!

Resources