Angular: When controller without $scope is required? - angularjs

see the code
<div ng-app="myApp" ng-controller="ctrlCarLists as cars">
<button ng-click="cars.showCars()">
Cars
</button>
<button ng-click="alert(cars.data)">
Test
</button>
</div>
var app = angular.module('myApp', []);
app.controller("ctrlCarLists", function () {
this.data = 'hello';
this.showCars = function () {
alert("Ford, Toyata, Mercedes");
};
});
i am new in angular so not being able to understand when people do not like to have $scope in controller. so please tell me or show me few scenario with example when people create controller without scope.
what is the meaning of this ctrlCarLists as cars ?
many people may say by this code ctrlCarLists as cars we are creating instance of controller to access property of controller but when we use $scope then controller instance is created too.
please help me to understand..
thanks

This is known as the 'controller as' pattern. For more info, check this and this link.

You can refer the this to a variable, just see the following code
var app = angular.module('myApp', []);
app.controller("ctrlCarLists", function () {
var self = this;
self.data = 'hello';
self.showCars = function () {
alert("Ford, Toyata, Mercedes");
};
});
and change your html to this
<div ng-app="myApp">
<div ng-controller="ctrlCarLists as cars">
<button ng-click="cars.showCars()">
Cars
</button>
</div>
</div>
'this' will an object in side the controller. you can see the data by write {{cars.data}}
in your example
self.showCars is a function smiler to $scope.showCars ,$scope.showCars smiler to $scope.data a variable can access in the controller.

Related

Ionic - AngularJS: calling methods via template outside of Controller

So, here's a sample code:
<div ng-controller="MyControllerOne">
<span ng-click="foobar()">Click Me!</span>
</div>
Can I, from that template, without changing controller, call the function foobar() in MyControllerTwo:
.controller('MyControllerOne', function($scope) {
//some code
})
.controller('MyControllerTwo', function($scope) {
// method I wanna call
function foobar(){
}
})
While not the prettiest solution, it is technically possible...ish.
If you update your HTML to:
<div ng-controller="MyControllerOne">
<span ng-controller="MyControllerTwo as mct" ng-click="mct.foobar()">Click Me!</span>
</div>
Then you should get your expected results.
You can call method which is in another controller from the template by injecting '$controller' service in the controller. Below is the demo and code.
You can see demo here: http://plnkr.co/edit/oBEKxamgJv0uDVsJJwth?p=preview
HTML:
<body ng-controller="MainCtrl">
<div ng-click="fooBar()">Click Me!</div>
</body>
JS:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $controller) {
$controller('SubCtrl', {$scope: $scope});
});
app.controller('SubCtrl', function($scope) {
$scope.fooBar = function() {
alert('second controller');
};
});
Pretty old question, but if any one is still looking for an alternative answer ...
It should be possible to use $emit or $broadcast.
Like from ControllerOne :
$rootScope.$broadcast('callToFoobat',{});
And then from ControllerTwo :
$scope.$on('callToFoobat', function(){
// whatever you want, so why not a call to foobar
})
Just a rough solution. Might be more elegant or lighter than just $rootScope.$broadcast. And maybe think about stoping propagation whenever needed.

Change ng-show in another controller?

I want to change ng-show in another controller than ng-show is.
myApp.controller('popupCtrl', function() {});
myApp.controller('changePopup', function($rootScope){
// now i wanna show my Ppopup
$rootScope.popup = true;
});
<div ng-controller="popupCtrl">
<div ng-show="popup">
Popuptext
</div>
</div>
But this doesn't work... How can I fix it?
Thanks!
So first thing, you should never add to the $rootScope or change it in anyway. It has been optimised by the angular team.
Second thing, there is no need to involve the $rootScope.
Here is a demo showing how to communicate across two controllers.
The key is the event aggregator pattern:
Communicator.register(function (newValue) {
vm.value = Communicator.value;
});
I created a function in the Communicator to register a callback function. The aim is that when a value gets changed the callback function is fired off. I.e. an event is triggered (change event).
The second key part is fire that change event off:
Communicator.change(!Communicator.value);
Here we pass through to the change function a new value which will do two things:
Update the internal value so we can keep track of it
Loop through all the registered callbacks and execute them passing in the new value.
By implementing this pattern, we can minimise the extent to which we communicate around our application ($rootScope can have a tendency to traverse the scope heirarchy when you $broadcast).
Now we can follow more closely the principle of single responsibility. Our class is aptly named in its current scope, when we look at this factory we can tell it is supposed to "communicate".
Finally, with a global event aggregator pattern ($rootScope) it is far more difficult to keep track of where these events are being broadcast from, and where they'll end up. Here we don't have that issue
One way to solve this is to use $rootScope.$broadcast
Here is an example: http://plnkr.co/edit/EmJnZvXFRWv6vjKF7QCd
var myApp = angular.module('myApp', []);
myApp.controller('popupCtrl', ['$rootScope', '$scope', function($rootScope,$scope) {
$scope.popup = false;
$rootScope.$on('changePopup', function(event, data) {
$scope.popup = !$scope.popup;
});
}]);
myApp.controller('changePopup', ['$rootScope', '$scope', function($rootScope, $scope) {
$scope.changePopup = function() {
$rootScope.$broadcast('changePopup', 'data could be sent here');
}
}]);
View:
<div ng-controller="popupCtrl">
<div ng-show="popup">
Popuptext
</div>
<div ng-controller="changePopup">
<button ng-click="changePopup()">Change the popup</button>
</div>
Using a service/factory is a better solution for cross controller communication if you are working on a large application, but for a smaller app I would say using $broadcast, $emit and $on is sufficient.
Here is a working demo for you - sorry I changed the controller names, but I am sure you will be able to build on this. Good luck
angular.module('myApp', [])
.controller('c1', function($scope) {
// now i wanna show my Ppopup
$scope.popup = false;
$scope.$on('popup', function() {
$scope.popup = true;
});
})
.controller('changepopup', function($rootScope, $scope) {
// now i wanna show my Ppopup
$scope.clicker = function() {
$rootScope.$broadcast('popup')
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="c1">
<div ng-show="popup">
Popuptext
</div>
</div>
<button ng-controller="changepopup" ng-click="clicker()">Click me</button>
</div>

Angular Controller as NewController 2 way binding works with this.function

I'm trying to understand why I must use the as in order that the two-way binding will work with this inside a controller.
working example:
<div ng-controller="MyController as TestController">
{{TestController.test()}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('MyController', function(){
this.test = function test(){
return "test";
};
});
</script>
not working example:
<div ng-controller="MyController">
{{MyController.test()}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('MyController', function(){
this.test = function test(){
return "test";
};
});
</script>
If you want to use this in your controllers you need to use the controller as syntax otherwise you have to use $scope in your controllers. If you didn't use controller as the controller would need to be:
app.controller('MyController', function($scope){
$scope.test = function test(){
return "test";
};
});
and the view would need to be:
<div ng-controller="MyController">
{{test()}}
</div>
One of the benefits of the controller as syntax is it helps to promote the use "dotted" object in the View which helps to avoid any reference issues that may occur without "dotting". For more info on scope reference issues take a look at this post
Not really an answer to your question, but normally you'd define functions you want to invoke from the DOM on the Controller's $scope.
Example:
<div ng-controller="MyController">
{{test()}}
</div>
<script>
var app = angular.module('myApp', []);
app.controller('MyController', function($scope){
$scope.test = function test(){
return "test";
};
});
</script>
http://plnkr.co/edit/lbgG9MCJ1kNBhArLpEpc?p=preview
Edit: Sorry, forgot to update the code in my post. The plnkr should've been right all along though.
Thanks to Wayne Ellery:
It's because Angular added the controller as syntax in 1.2 which enables you to work with this. ng-controller="MyController as myController". Think of it as var myController = new MyController();. It's essentially scoping an instance of MyController to myController.

AngularJS: ng-app inside ng-include

I have a template like this.
<body ng-app="demo" ng-controller="demo">
<div ng-include="/main.html">
</div>
</body>
And the main.html is.
<div ng-app="main" ng-controller="main>
""
</div>
here is the js.
JS-1
var myapp = angular.module('demo', []);
myapp.controller('demo', function($scope,$routeParams, $route,$http) {
$scope.variable="444"
})
JS-2
var mainapp = angular.module('mainapp', []);
myapp.controller('main', function($scope,$routeParams, $route,$http) {
})
Is it possible to access the scope of JS-1 inside JS-2?, if yes how, if no is there any solution to this.Thanks.
It depend what you want to do.
If you want read $scope.variable variable from JS-1, you should see it in JS-2 $scope.
If you want modify $scope.variable form JS-1, you should create method in JS-1:
$scope.changes = function(data){
$scope.variable = data;
}
This method also should be available in JS-2 $scope.
This isn't nice solution but should work.
The best solution is to create service which will provide operations on JS-1 fields.

Angular binding model in scope issue?

Hi I am new to the angular js and trying to write the chat application using the socket io and angular js with ionic for android platform. But in my chat page there is one issue.
I am trying to bind the textbox to the $scope.message variable using ng-model but it is not getting bind as the test when i show the same variable value in page itself it works as it is but in controller i gets value as undefined or empty
index.html
<body ng-app="farmApp" ng-controller="farmAppController" >
<ion-content>
<ul id="Messeges">
<li class="right">Welcome to Chat</li>
<li ng-repeat="chatMessage in messages">
{{chatMessage}}
</li>
</ul>
<form ng-submit="sendMessage()">
<input placeholder="Your message" ng-model="message">
<input type="submit" name="send" id="send" value="Send" class="btn btn-success">
<br/>
{{message}} //This updates the value as i type in textbox
</form>
</ion-content>
</body>
but when i see print that model on console it shows undefined when i define at the start in controller then it shows empty value
Controller.js
var farmAppControllers = angular.module('farmAppControllers',[]);
farmAppControllers.controller('farmAppController',['$scope','socket',function($scope,socket){
$scope.messages = [];
$scope.message = ''; //When i don't declare then console shows undefined on sendMessage function if declared then empty
socket.on("update", function (data) {
console.log(data);
$scope.messages.push(data);
});
$scope.sendMessage = function (){
console.log($scope);
console.log($scope.message); // This shows undefined or empty on console
socket.emit("msg",$scope.message);
$scope.messages.push($scope.message);
$scope.message ='';
};
}]);
My app.js
'use strict';
var farmApp = angular.module('farmApp', ['farmAppControllers','farmAppServices','ionic']);
And services.js for socket wrapper
var farmAppServices = angular.module('farmAppServices',[]);
farmAppServices.factory("socket",function($rootScope){
var socket = io.connect();
return {
on:function (eventName,callBack){
socket.on(eventName,function(){
var args = arguments;
$rootScope.$apply(function(){
callBack.apply(socket,args);
});
});
},
emit:function(eventName,data,callBack){
socket.emit(eventName,data,function(){
var args = arguments;
$rootScope.$apply(function(){
if(callBack){
callBack.apply(socket,args);
}
});
});
}
};
});
i stuck here... i try to google it but not able to solve it. In case of confusion feel free to comment. Any help would be great.
UPDATE
When i used the first answer of this question the problem got solved but still not clear why ng-submit is not working ? Any Idea Why ? Because it seems i am still unable to update the view scope from the controller ?
I think the problem is <ion-content> which is a directive and seems to create its own scope. From the docs:
Be aware that this directive gets its own child scope. If you do not understand why this is important, you can read https://docs.angularjs.org/guide/scope.
Therefore your message property isn't in the scope of your controller.
Objects are passed by reference and sendMessage is a function respectively an object, thats why it's still called correctly from the child scope.
What you should do is create an object with a name that makes sense to "package" the properties you want to share.
$scope.package = {}
$scope.package.messages = [];
$scope.package.message = 'You default message...';
And then in your function:
$scope.package.messages.push($scope.package.message);
And in your template:
<input placeholder="Your message" ng-model="package.message">
Here is a plunker with a working solution. It throws some random errors, I actually don't know ionic. But the example works and everything else doesn't matter.

Resources