AngularJS data binding not working - angularjs

I wrote some simplified code on http://jsfiddle.net/gsche/1/
When I click the "Refresh" link, the "customer.name" model doesn't update the view.
I wrote the code on my local computer and debugged it with Batarang in Chrome.
The console doesn't show any errors. The Model page in Batarang shows the customer name changing on the right, associated with an old scope id, but the id's of the $scopes also change.
Can anyone point me in the right direction?
<div ng-app>
<div ng-controller="MainCtrl">
<p> Refresh </p>
<p>
<input type="text" ng-model="customer.name">
</p>
<p>{{ customer.name }}</p>
</div>
</div>
function MainCtrl($scope) {
$scope.customer = {
name: 'TTT',
id: 0
};
$scope.Refresh = function ($scope) {
$scope.customer.name = 'Test';
};
}
Update 1 08.08.2013
Thank you all (#EpokK, #Stewie, #Hippocrates). I undestand now the problem with jsfiddle, and the example works as it should.
However, in my test application, the {{customer.name}} binding works, but the "Refresh" click still doesn't change the {{customer.name}} in the view.
Here is the content of my application. I think it is the same as the jsfiddle example:
index.html
<!doctype html>
<head>
<title>Test</title>
</head>
<body ng-app="roaMobileNgApp">
<script src="scripts/angular.js"></script>
<script src="scripts/angular-ui.js"></script>
<link rel="stylesheet" href="scripts/angular-ui.css">
<div class="container" ng-view=""></div>
<script src="scripts/app.js"></script>
<script src="scripts/controllers/main.js"></script>
</body>
</html>
app.js
'use strict';
angular.module('roaMobileNgApp', ['ui'])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
});
main.js
'use strict';
angular.module('roaMobileNgApp')
.controller('MainCtrl', function ($scope) {
$scope.customer = {name: '',
id: 0};
$scope.getDetails = function() {
$scope.customer.name = 'Test';
};
});
main.html
<div ng-controller="MainCtrl">
Refresh
<p><input type="text" ng-model="customer.name"> {{ customer.name }} </p>
</div>

Check my solution, I have edit your JSFiddle: http://jsfiddle.net/gsche/10/
function MainCtrl($scope) {
$scope.customer = {
name: 'TTT',
id: 0
};
$scope.getDetails = function () {
$scope.customer.name = 'Test';
};
}

Just select "No wrap - in " in fiddle options (because otherwise your demo won't work), and remove the $scope parameter from your Refresh function. You don't need to pass in $scope because the function itself is defined inside the $scope.
$scope.getDetails = function(){
$scope.customer.name = 'Test';
};

It's just the way you loaded your scripts.
I like to load angular followed by my app.js containing controllers right at the end of the body:
...
<script src="/assets/js/angular.min.js"></script>
<script src="/assets/js/app.js"></script>
</body>
To get your fiddle working, all I did was change it from "onReady" to "in body" (It's the little dropdown near the top left.)
Check this out: http://jsfiddle.net/gsche/3/
onReady means your controller definition was wrapped in an onReady function by jsfiddle. By the time angular loaded and got to work, your controller was still undefined and angular had to go ahead and spit out the raw template.

Related

Angular expression not updated upon button press

I can successfully update an Angular expression immediately but it fails upon a button press. I need a little help here.
Here's the code.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
<div ng-app="MyApp">
<div ng-controller="MyController">
<button id="myButton">Press</button>
{{myMessage}}
<script>
function setMessage(msg) {
angular.module('MyApp', [])
.controller('MyController', function($scope) {
$scope.myMessage = msg;
});
}
setMessage("first");
$(document).ready(function() {
$('#myButton').on('click', function( event ){
setMessage("second");
});
});
</script>
</div>
</div>
</body>
</html>
The first call which happens right away correctly updates the expression to "first". However the second call when the button is pressed fails to upate the expression to "second". What am I doing wrong?
First of all, good advice: remove jQuery from the project until you understand well why you should not use jQuery-style development with Angular app. Shortly, Angular has a specific event/parsing/compiling lifecycle that is not the same as just the flow we are used in jQuery projects. Take a look at this thread.
Then what you need to do is to use ngClick directive:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<div ng-app="MyApp">
<div ng-controller="MyController">
<button ng-click="setMessage('second')">Press</button>
{{myMessage}}
</div>
</div>
<script>
angular.module('MyApp', [])
.controller('MyController', function($scope) {
$scope.myMessage = 'first';
$scope.setMessage = function(msg) {
$scope.myMessage = msg;
};
});
</script>
Remove the function around your angular module and you should use angular's ng-click directive to update your html on click:
<div ng-app="MyApp">
<div ng-controller="MyController">
<button id="myButton" ng-click="update('second')">Press</button>
{{myMessage}}
<script>
angular.module('MyApp', [])
.controller('MyController', function($scope) {
$scope.myMessage = "first";
$scope.update = function(msg){
$scope.myMessage = msg;
}
});
</script>
</div>
</div>
The documentation for ng-click: https://docs.angularjs.org/api/ng/directive/ngClick
Don't mix jQuery with angularjs, unless is totally needed. See this answer about it
you should use all the events, functions and directives providad by angularjs.
So your coude would look to something like this
<div ng-app="MyApp">
<div ng-controller="MyController">
<button ng-click="setMessage()">Press</button>
{{myMessage}}
<script>
function setMessage(msg) {
angular.module('MyApp', [])
.controller('MyController', function($scope) {
// set the original value for myMessage
$scope.myMessage = "first";
// update with second value
$scope.setMessage = function(){
$scope.myMessage = "second";
}
});
}
</script>
</div>
</div>
Of course you should organize this better, but this is the first approach
The main difference is that if you use the angular events (like ng-click in this case) it will let Angular knows what something has changed and that it has to update/refresh the view.
If you change something with jQuery, unless you force angular to know it (using $scope.$apply()) there is no way that angular knows by itself that the model has changed.

angular - Switch navbar when view is changed

I am using angular-route.min.js and I have two designs for my navbar.
The First one is the landing page navbar that will appear first on my index.html.
The second navbar is when the user is routed to the /signin page.
I am unsure on how to go about this. I see a lot of different ways that this could be done, but none really that explain how I could change the entire header view when another route is chosen. They just show how to change the links that are contained inside of it. Like this Stack
how can I switch out the header when it is routed to the /signin page?
also, I am working with another person who is doing the backend with Django. That is why I changed the "{{ }}" to "[[ ]]".
var app = angular.module('app', ['ui.bootstrap', 'ngRoute']);
app.config(function($interpolateProvider, $routeProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
$routeProvider
.when('/', {
templateUrl: 'pages/LandingPage.html',
})
.when('/signin', {
templateUrl: 'pages/SignIn.html'
})
.when('/contact', {
templateUrl: 'pages/contact.html'
});
});
<!DOCTYPE html>
<html lang="en" data-ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js">
</script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular-route.js">
</script>
</head>
<body>
<div ng-view></div>
</body>
</html>
I think ng-include directive could solve the situation you are facing.
In controller code.
.controller('HeaderCtrl', function($scope, $location) {
$scope.$on('$locationChangeSuccess', function(/* EDIT: remove params for jshint */) {
var path = $location.path();
//EDIT: cope with other path
$scope.templateUrl = (path==='/signin' || path==='/contact') ? 'template/header4signin.html' : 'template/header4normal.html' ;
});
})
In Html.
<body>
<div ng-controller="HeaderCtrl">
<div ng-include="templateUrl"></div>
</div>
<div ng-view></div>
</body>
I hope this could help you. :)
The difference of your two navbars are not significant. An alternative is just use ng-class and ng-show to give different styles.
For example, in the navbar.html:
<nav>
<span ng-show="isNormalPage">Inn</span>
<img ng-class="{align-center: isNormalPage}">Logo</img>
<span ng-show="isNormalPage">Sing in</span>
</nav>
In your JS file, add a flag to mark singin page:
.when('/signin', {
controller: [$scope, function ($scope) {
$scope.isNormalPage = false;
};
}]
})

AngularJS : How to get a sub-total from my directive using ng-repeat?

I have a situation where I'm using an ng-repeat to display a directive, and this directive is responsible for calculating a sub-total and using 2-way binding to add that sub-total to my total.
However, by using the ng-repeat, it's adding to the scope of the ng-repeat instead of my controller. How can I get this to work correctly?
Edit: I figured out a solution, but not sure if it's the best way to do it...
I changed:
<div ng-repeat='item in myArray'>
<add-it-up sub-total='total1'></add-it-up>
</div>
to
<div ng-repeat='item in myArray'>
<add-it-up sub-total='$parent.total1'></add-it-up>
</div>
and it's working. Is there a better way to do this?
Plunker: http://plnkr.co/edit/lqh0z93yc5Q5E2gNBdtG?p=preview
<!DOCTYPE html>
<html ng-app='testApp'>
<head>
<script data-require="angular.js#1.3.15" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js"></script>
</head>
<body ng-controller='TestCtrl'>
<!-- This doesn't work -->
<div ng-repeat='item in myArray'>
<add-it-up sub-total='total1'></add-it-up>
</div>
{{total1}}
<br />
<!-- This does work -->
<add-it-up sub-total='total2'></add-it-up>
<add-it-up sub-total='total2'></add-it-up>
<add-it-up sub-total='total2'></add-it-up>
{{total2}}
<script>
var app = angular.module('testApp', []);
app.controller('TestCtrl', ['$scope', function($scope) {
$scope.myArray = [0, 1, 2];
$scope.total1 = 0;
$scope.total2 = 0;
}])
app.directive("addItUp", function () {
return {
restrict: 'E',
scope: {
subTotal: "="
},
controller: ['$scope', '$timeout', function ($scope, $timeout) {
$timeout(function() {
console.log($scope.subTotal)
$scope.subTotal += 5;
console.log($scope.subTotal)
})
}]
}
})
</script>
</body>
</html>
You have to add an object to your $scope containing the total1. Otherwise this property gets overwritten by the ng-repeat sub-scopes:
$scope.totals = {
total1: 0,
total2: 0
};
Have a look at this updated plnkr. For more information visit Understanding Scopes.

Cannot inject view with angularjs 1.2

My code, as below, does not substitute the mg-view with the template from the route configuration.
I get {{message}} to be replaced by 'in controller', which shows the controller is alive, but nothing more happens.
View:
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="angularjs/angular.js"></script>
<script src="angularjs/angular-resource.js"></script>
<script src="angularjs/angular-route.js"></script>
<script src="app.js.html"></script>
</head>
<body class="appearanceOrange styleIOS">
<section ng-app="app" ng-controller="pageCtrl">
Current page '{{ message }}'
<div ng-view></div>
</section>
</body>
</html>
Controller:
var app = angular.module('app', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/corporate', {
controller:'pageCtrl',
templateUrl:'corporate.html'
})
.otherwise({
redirectTo:'/corporate'
});
});
app.controller('pageCtrl', function ($scope) {
$scope.message = "in controller";
});
Partial:
<section
id="pageCorp"
class="page"
title="Corp France"
background="stripRoll"
style="text-align:center; display: block;">
<div style="padding:200px">
<a href="http://www.corp.fr/go/id/ceeq/" style="color: white">
<img src="rsc/corp.logo.svg" style="width:150px; margin: auto auto;background-color:white;"/><br/>
<span style="font-size:18pt;font-weight:bold">visit our Website</span>
</a>
</div>
</section>
Looks fine to me, as long as your template in corporate.html exists.
Here is a working fiddle.
var app = angular.module('app', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider.when('/corporate', {
controller: 'pageCtrl',
template: 'hi'
}).otherwise({
redirectTo: '/corporate'
});
});
app.controller('pageCtrl', function($scope) {
$scope.message = "in controller";
});
Edit: Here is another possibility to use the template, with $templateCache: jsfiddle
app.run(function($templateCache) {
$templateCache.put('corporate.html', 'This is the content of the template');
});
After hours of investigation, it comes that legacy javascript was breaking angularjs.
So be careful when converting (migrating) to angularjs, and try to deactivate your legacy javascript code first, prior to enter in a lengthly investigation period…
Thanks to everyone who helped me.

Use ng-controller and $routeProvider at the same time

The issue is that I have an index page, whith a(some) partial(s) view(s) that we can call "A.html" with a controller "ACtrl" assigned by $routeProvider, but inside that partial view, I would like to use a different controller for some divs using ng-controller to include a "A1Ctrl".
Is this possible?
Not focus on any code, but in the concept if this is barely possible and how?
I tried to include in the partial view something like this with no success:
A.html
... //Other stuff for this partial view
<div ng-controller="A1Ctrl">
{{message}}
</div>
... //More stuff for this partial view
I have included the .js where the A1Ctrl is defined to the index page with same result. Any tip?
UPDATE:
I have create in plnkr a sample code to show what I want to do: http://plnkr.co/edit/hdpLMK3DbzNdz2KeHPEB?p=preview
I have partial view generated after clicking "Say hi" which has its own template ("first.html") and controller, injected by the $routeProvider. But in that partial view in first.html I want to add a which has its own controller for only that section of code. But I can't make it work, any suggestion?
I also tried to use Dependency Injection to include the module "multilinguage" into router.js with no success because it seems to generate an error.
index.html
<html ng-app="plunker">
<head>
... //Other imports
<script src="app.js"></script>
<script src="router.js"></script>
<script src="multilanguage.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
Say hi |
Say bye
<br/>
<div ng-view=""></div>
</body>
</html>
first.html
{{message}}
<div ng-controller="MultiLang">
{{message}}
</div>
router.js
var app = angular.module('router', ['ngRoute', 'multilanguage']).
config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.
when("/first", {
templateUrl: "first.html",
controller: "EngLang"
}).
when("/second", {
template: "Bye man!"
});
});
app.controller('EngLang', function($scope) {
$scope.message = 'Hi guys';
});
multilanguage.js
angular.module('multilanguage', []).
controller('MultiLang', function($scope){
$scope.message = "Hallo, Hola, Ciao, Ni Hao"
});
Thanks in advance.
Yes, also you can use nested controllers, for example:
<div ng-controller="A1Ctrl">
{{ message }}
<div ng-controller="subCtrl">
{{ message }}
</div>
</div>

Resources