Use this instead $scope on controller with provider - angularjs

I´m learning about Providers. On a common controller I would use
modu.controller("thecontrol", [function()
{
this.something = "Hello";
]});
and on the HTML
<div ng-controller="thecontrol as ctrl">
{{ ctrl.something }}
</div>
But... I´m trying to the the same with this code and, I really could not, even when I tried all the ways I "know".
Here´s the code...
What I want? Use THIS instead of $scope
<div ng-app="myApp" ng-controller="showingName">
{{theNameIs}}
</div>
<script src="angular.js"></script>
<script>
var myApp = angular.module("myApp", []);
myApp.provider("showingName", function() {
this.name = "Luis";
this.$get = function() {
var name = this.name;
return {
showName: function() {
return name;
}
}
};
this.setName = function(name) {
this.name = name;
};
});
myApp.config(function(showingNameProvider){
showingNameProvider.setName("Juan");
});
myApp.controller("showingName", function($scope, showingName)
{
$scope.theNameIs = showingName.showName();
});
</script>
And yes... It works, but I would like to know if it´s possible to do it with THIS.
Thanks!

I think it's because when you don't name the controller, then the {{ }} has to be scope, since this and $scope can be different depending on the context. Say for instance in an ng-repeat, 1 controller yet essentially 2 scopes.
Name the controller like you did on the first, ctrl as showingName. Make the variable this.theNameIs and then use {{ ctrl.theNameIs }}
Also, personally I don't think you should name the controller and provider the same name, appreciate this is probably just an example.
More information on $scope and this:
'this' vs $scope in AngularJS controllers

Related

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.

Scope values to a requested content

I have a view that contains a button, when the button is clicked, a $http.get request is executed and the content is appended on the view.
View:
<button ng-click="includeContent()">Include</button>
<div id="container"></div>
Controller:
$scope.includeContent = function() {
$http.get('url').success(function(data) {
document.getElementById('container').innerHTML = data;
}
}
The content to include:
<h1>Hey, I would like to be {{ object }}</h1>
How can I scope a value to object? Do I need to approach this in a complete different way?
The built-in directive ng-bind-html is the way you are looking for.
Beware, that ng-bind-html requires a sanitized string, which is either done automatically when the correct libary is found or it can be done manually ($sce.trustAsHtml).
Don't forget to inject $sce in your controller.
$scope.includeContent = function() {
$http.get('url').success(function(data) {
$scope.data = $sce.trustAsHtml(data);
}
}
<button ng-click="includeContent()">Include</button>
<div ng-bind-html="data"></div>
As you also want to interpolate your requested HTML, I suggest using $interpolate or, if it can contain whole directives or should have a full fledged two-way-data-binding, use $compile instead.
In your case alter the assignment to
$scope.data = $sce.trustAsHtml($interpolate(data)($scope));
Don't forget to inject $interpolate/$compile aswell.
As I don't know about your $scope structure I assume that "object" is available in this scope. If this isn't the case then change the $scope parameter to whatever object contains your interpolation data.
You should use a controller to do this (I imagine you are since you're using $scope).
ctrl function () {
var ctrl = this;
ctrl.includeContent = function () {
$http.get("url").success(function (data) {
ctrl.object = data;
});
};
}
<div ng-controller="ctrl as ctrl">
<button ng-click="ctrl.includeContent()">Include</button>
<div id="container">
<h1 ng-show="ctrl.object">Hey, I would like to be {{ctrl.object}}</h1>
</div>
</div>
You need not select an element and append the data to it. Angular does it for you. That's what is magic about angular.
In your controller's scope, just update object and angular does the heavy-lifting
$scope.includeContent = function() {
$http.get('url').success(function(data) {
$scope.object = data;
}
}
If that's html code from a server, then you should use the 'ng-bind-html' attribute:
<button ng-click="includeContent()">Include</button>
<div id="container" ng-bind-html="htmlModel.ajaxData"></div>
Controller:
$scope.htmlModel = {ajaxData:''};
$scope.includeContent = function() {
$http.get('url').success(function(data) {
$scope.htmlModel.ajaxDataL = data;
}
}
One way is to use ng-bind-html as suggested.
Another way is with $compile:
app.controller('MainCtrl', function($scope, $http, $compile) {
$scope.error='error!!!';
$scope.includeContent = function() {
$http.get('url').success(function(data) {
var elm = angular.element(document.getElementById('container')).html(data);
$compile(elm)($scope);
}).error(function(){
var elm = angular.element(document.getElementById('container')).html('{{error}}');
$compile(elm)($scope);
})
}
});
Also, typically in angular, when you want to manipulate the DOM you use directives.
DEMO

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 : ng-if with dictionaries

Kind new to AngularJS I'm encountering the following problem :
How could eval with ng-if if a dictionary is empty or not ?
With arrays ng-if="myArray.length" works great but doesn't with dictionaries.
Edit : Also already tried Object.keys(myDict).length which doesn't work.
ng-if is also able to evaluate a function in scope.
For example:
<div ng-if="functionHere(x)" ></div>
Then in your controller, you could have
$scope.functionHere = function(input) { if [logic here]..... }
So, if you could contain your logic in a javascript function, then you could delegate the ng-if's decision to what the function returns.
JSFiiddle Example
Use a scope function:
html:
<div ng-app="myModule" ng-controller="myController">
<div ng-if="!isEmptyObject(myObj)">
<h1>Hello</h1>
</div>
</div>
javascript:
angular.module('myModule', [])
.controller('myController', ['$scope', function($scope) {
$scope.isEmptyObject = function(obj) {
for(var prop in obj) {
if(obj.hasOwnProperty(prop))
return false;
}
return true;
}
$scope.myObj = {};
}]);
Check out this fiddle

Angularjs different controllers for one include

I want to have element where i can have 2 views using their own controller but only one at a time.
I can't use a ng-view and use the routeProvider because in the future I need to include more ng-includes that need to change their content depending on the possible actions.
I created a fiddle http://jsfiddle.net/EvHyT/29/.
So I used a ng-include and then I set the src for it from a main controller. At that point I want to use controller 1 or controller 2.
function MainCtrl($rootScope, $scope, navService){
$scope.template = {};
$scope.loadCtrl1=function(param){
navService.loadCtrl1(param);
}
$scope.loadCtrl2=function(param){
navService.loadCtrl2(param);
}
$rootScope.$on('loadCtrl1', function(e, args){
$scope.template = {'url': 'temp1'};
});
$rootScope.$on('loadCtrl2', function(e, args){
$scope.template = {'url': 'temp2'};
});
}
I use a service for communication because i want to move the load controller functions in a child controller.
var myApp = angular.module('myApp',[]);
myApp.factory('navService', function($rootScope) {
return {
loadCtrl1:function(param){
$rootScope.$broadcast('loadCtrl1', {'id':param});
},
loadCtrl2:function(param){
$rootScope.$broadcast('loadCtrl2', {'id':param});
}
};
});
I know this solution is bad because the controllers are not yet created when a different template is inserted so my event listener will not fire. Also can I destroy the previous instances of the controller because switching between the two controllers makes my event fire multiple times.
function Child1Ctrl($scope, $rootScope){
$rootScope.$on('loadCtrl1', function(e, args){
alert(args.id);
});
}
function Child2Ctrl($scope, $rootScope){
$rootScope.$on('loadCtrl2', function(e, args){
alert(args.id);
});
}
You don't need to broadcast (and shouldn't be broadcasting) to make this happen.
In my experience, if you're broadcasting on the rootScope, you're probably working too hard.
A simpler way of loading the template is very similar to what you're doing:
my.NavService = function() {
this.template = 'index.html';
this.param = null;
};
my.NavService.prototype.setTemplate(t, p) {
this.template = t;
this.param = p;
};
my.ctrl = function($scope, nav) {
$scope.nav = nav;
$scope.load = function(t, p) {
nav.setTemplate(t, p);
};
};
my.ctrl1 = function($scope, nav) {
$scope.param = nav.param;
};
my.ctrl2 = function($scope, nav) {
$scope.param = nav.param;
};
module.
service('nav', my.NavService).
controller('mainCtrl', my.ctrl).
controller('ctrl1', my.ctrl1).
controller('ctrl2', my.ctrl2);
<script type="text/ng-template" id="temp1.html">
<div ng-controller="ctrl1">Foo {{param}}.</div>
</script>
<script type="text/ng-template" id="temp2.html">
<div ng-controller="ctrl2">Bar {{param}}.</div>
</script>
<div ng-controller="mainCtrl">
<a ng-click="load('temp1.html', 16)">Load 1</a>
<a ng-click="load('temp2.html', 32)">Load 2</a>
<div ng-include src="nav.template"></div>
</div>
A setup like this would work much better for you.
Alternatively, you should look into selectively showing elements with ng-switch. Unlike ng-show/hide, ng-switch does not simply add "display:none" to the CSS. It removes it from the DOM.
Some notes:
The above example may not be a working example, it's a demonstration of the idea.
A working example can be seen here: http://jsbin.com/ofakes/1 It modifies your original code.
JSFiddle had some issues with loading the include from the on page script
tag.
JSBin was a little better.
I didn't really get it to work as expected until I broke out the templates
into their own files.

Resources