Angular 1.5 - Component() Method - angularjs

I'm trying to get the component method working which is new for Angular 1.5. So far I acheived the following see my jsFiddle JSFIDDLE. For some reason I can not get the templateUrl working so that I can see the html template with the defined scope. Any help would be great.
JSFIDDLE
JS
var app = angular.module('myApp', []);
app.controller('mainCtrl', function($scope) {
$scope.name = "Tony Danza";
});
app.component("myBox", {
bindings: {},
controller: function($element) {
var myBox = this;
myBox.game = 'World Of warcraft';
},
controllerAs: 'myBox',
templateUrl: "/template",
transclude: true
})
HTML
<div ng-app="myApp" ng-controller="mainCtrl">
<script type="text/ng-template" id="/template">
<div style='width:40%;border:2px solid black;background-color:yellow'>
Your Favourite game is: {{myBox.game}}
</div>
</script>
Hi {{name}}
<div my-box>
</div my-box>
</div><!--end app-->

Angular components must be elements. Use <my-box> instead of <div my-box>.
The documentation on Components doesn't make this immediately clear, but it is documented.
when you want a directive that is triggered by an attribute or CSS class, rather than an element
The directive/component comparison table also explains that restrict is unavailable for components and they are always elements.

Related

Angular 1.5 Pass data from component to controller

I have component inside of the controller and i'm binding the data to it. How to make changes in component visible in the controller.
I have that code:
JS
app.controller('TheCtrl', function($scope) {
$scope.changeable = 'earlier';
});
app.component('innerComponent', {
bindings: {
changeable: '='
},
controller: function() {
this.changeable = 'later';
}
}
HTML
<div ng-controller="TheCtrl">
<inner-component changeable="val"></inner-component>
<p>
{{changeable}}
</p>
</div>
And it doesn't change the 'changeable' value in the view of the controller (it show "earlier" value). Why? How to make the changes visible in the controller?
It does work as expected.
function appCtrl() {
this.value = "test";
}
var inner = {
bindings: {
changeable: '='
},
controller: function() {
this.changeable = 'later';
}
};
angular.module('app', []);
angular.module('app')
.controller('appCtrl', appCtrl)
.component('inner', inner);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="appCtrl as ctrl">
<inner changeable="ctrl.value"></inner>
<p>
{{ctrl.value}}
</p>
</div>
</div>
However you shouldn't use components for building MVW apps.
You either go all the way and create a component root with children components or use "controlled divs".
But hybrid MVC/components apps are bad architecture.

Creating directive AngularJS without $scope

I´m learning AngularJS. Now I´m trying the directives. I created a directive but I can´t make it work. I can do it with $scope, but I want to know HOW to do it without it.
The code:
<div ng-app="myApp" ng-controller="controls">
<div the-name></div>
</div>
<script src="angular.js"></script>
<script>
var modu = angular.module("myApp", []);
modu.controller("controls", [function() {
var self = this;
self.user = {
name : "Pedro",
lastname: "Delgado"
};
}]);
modu.directive("theName", [function() {
return {
template: 'Name: {{user.name}}'
};
}]);
</script>
An the RESULT is:
Name:
And I want:
Name: Pedro
Anyone can help me?
Thanks a lot!
It's called controller-as syntax. You need to create an alias to controller in the template:
<div ng-app="myApp" ng-controller="controls as ctrl">
<div the-name></div>
</div>
and then in directive template use {{ctrl.user.name}}.
But ideally, you isolate the scope of the directive, because you don't want it to know about its surroundings and what controllerAs alias is used.
This version of your directive will be much more reusable:
modu.directive("theName", [function() {
return {
scope: {
user: '='
},
template: 'Name: {{user.name}}'
};
}]);
and usage is:
<div ng-app="myApp" ng-controller="controls as ctrl">
<div the-name user="ctrl.user"></div>
</div>
So in this case, directive (and template) doesn't know anything about environment it's used (about controller prefix, etc), it only cares that proper user object was passed in it. This is the point of isolated scope.

Angularjs directive, call same directive from within itself

I am building generic angularjs directive to support editing of json object. I have json data and also admin data to have details about original data. Following code details which I am using to build my generic directive.
Please refer Plunker for running code.
http://plnkr.co/edit/x2lqHjYq48gwxW7oYyEQ?p=preview
Directive Code:
app.directive("objecteditor", [function () {
return {
restrict: "E",
templateUrl: "ObjectEditor.html",
replace: true,
scope: {
object: '=',
objectAdmin: '='
},
link: function (scope, element, attrs) {
//Method to initialize
scope.init = function () {
};
//Call init() to initialze the loading.
scope.init();
}
};
}]);
Directive Template:
<div>
<h4 data-ng-bind-template="{{objectAdmin.displayName}}"></h4>
<div data-ng-repeat="column in objectAdmin.objectDefinition">
<div data-ng-switch="column.type">
<div data-ng-switch-when="string">
<label class="label-plain" data-ng-bind-template="{{column.displayName}}"></label>
<input type="text" data-ng-model="object[objectAdmin.name][column.name]" placeholder="{{displayName}}" title="{{displayName}}" name="textBox{{name}}" required />
</div>
<!--Call same object for child type as object. But how??? If i call <object> directive here then goes into infinite cycle -->
<div data-ng-switch-when="object">
</div>
</div>
</div>
</div>
Controller Code:
var app = angular.module("myApp", []);
app.controller('ApplicationController', ['$scope',
function($scope) {
//Method to initialize
$scope.init = function() {
//Set json data strucutre for editing
$scope.objectAdmin ={"name":"bankinfo","displayName":"Bank Info","type":"object","objectDefinition":[{"name":"name","displayName":"Bank Name","type":"string"},{"name":"mainPhone","displayName":"Main Phone","type":"string"},{"name":"contact","displayName":"Contact","type":"object","objectDefinition":[{"name":"name","displayName":"Name","type":"string"},{"name":"title","displayName":"Title","type":"string"}]}]};
$scope.object={"bankinfo":{"name":"Chase Bank - Newburgh","mainPhone":"1 (845) 333-3333","contact":{"name":"Donna Shuler","title":"Commercial Accounts Mgr."}}};
};
//Call init() to initialze the loading.
$scope.init();
}
]);
Index.html
<!doctype html>
<html ng-app='myApp'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="script.js"></script>
<script src="ObjectEditor.js"></script>
</head>
<body data-ng-controller="ApplicationController">
<h2>How to call same directive within itself?</h2>
<!--Use object editor directive to edit the object details -->
<objecteditor data-object="object" data-object-admin="objectAdmin"></objecteditor>
</body>
</html>
I want to make my directive generic so that same type of object editing can be supported by single directive.
When I tried to call same directive within itself then it fall into infinite loop (which is expected).
How can I achieve this functionality in directive?
Please help.
I was going through the recursive directive and came across following post which was helpful to implement my requirement.
https://www.packtpub.com/books/content/recursive-directives. Following is code to implement this.
Object Editor Directive Template:
<div>
<objecttree data-object="object" data-object-admin="objectAdmin" data-folder-guid="folderGuid" data-hide-header="'true'"></objecttree>
<script type="text/ng-template" id="objectTree">
<div class="clear-left">
<h4 data-ng-if="!hideHeader" data-ng-bind-template="{{objectAdmin.displayName}}"></h4>
<div data-ng-repeat="column in objectAdmin.objectDefinition">
<div data-ng-switch="column.type">
<imageeditor data-ng-switch-when="image" data-image="object[column.name]" data-folder-guid="folderGuid" data-column="column"></imageeditor>
<formcheckbox data-ng-switch-when="boolean" data-input-value="object[column.name]" data-editable="column.editable" data-name="column.name" data-display-name="column.displayName" data-formName="'resourceAddEditFormName'"></formcheckbox>
<addresseditor data-ng-switch-when="address" data-address="object[column.name]" data-column="column" data-collection-admin="objectAdmin"></addresseditor>
<formtextbox data-ng-switch-when="string" data-ng-if="!column.isDropdown" data-input-value="object[column.name]" data-editable="column.editable" data-name="column.name" data-display-name="column.displayName" data-formName="'resourceAddEditFormName'"></formtextbox>
<dropdownbox data-ng-switch-when="string" data-ng-if="column.isDropdown" class="admin-textbox" data-selected-id-list="object[column.name]" data-dropdown="column" data-multiple="column.dropdownTypeMultiple"></dropdownbox>
<div data-ng-switch-when="object">
<hr/>
<objecttree data-object="object[column.name]" data-object-admin="column" data-folder-guid="folderGuid" data-hide-header="'true'"></objecttree>
</div>
<div data-ng-switch-when="array">
<hr/>
<arrayobjecttree data-objects="object[column.name]" data-objects-admin="column" data-folder-guid="folderGuid" data-hide-header="'true'"></arrayobjecttree>
</div>
</div>
</div>
</div>
</script>
</div>
Object Tree:
app.directive("objecttree", ['$compile', '$templateCache', function ($compile, $templateCache) {
return {
restrict: "E",
scope: {
object: '=',
objectAdmin: '=',
folderGuid: '=',
hideHeader: '='
},
link: function (scope, element, attrs) {
element.replaceWith(
$compile(
$templateCache.get('objectTree')
)(scope)
);
}
};
}]);
This is Shankar. You can use the below solution for recursive directive.
Please confirm me whether this resolves your issue.If not, you can let me know.
As I'm not able to paste my entire code here, you can find the solution in my Github repository:(i.e. gmssankar/myRepository/Recursive Directive)
https://github.com/gmssankar/myRepository/blob/master/Recursive%20Directive
The code can be found in the following link too in plunker:
plnkr.co/edit/WrZekRS5AzfFJhQ2d3XK?p=preview
I'm not able to attach the complete code here as it restricts the number of lines. The logic is: Inside Directive template display bank name, main phone,contact name and contact title from the passed object. Then check if the passed object, has object definition (i.e child nodes). If yes, then extract each child using ng-repeat , and pass to same directive. Issue gets resolved here. From Github or plnkr , you can access the complete code.

ng-click attribute on angularjs directive

I think it should be easy to use the well known angular attributes on a directive out of the box.
For example if the name of my directive is myDirective I would like to use it this way:
<div ng-controller="myController">
<my-directive ng-click="doSomething()"><my-directive>
</div>
instead of needing to define a custom click attribute (onClick) as in the example below
<div ng-controller="myController">
<my-directive on-click="doSomething()"><my-directive>
</div>
It seems that ng-click can work, but then you need to specify ng-controller on the directive tag too which I don't want. I want to define the controller on a surrounding div
Is it possible to use ng-click on a directive together with a controller defined on a parent html element?
Here is updated code. Maybe is this what you were looking for.
Html:
<div data-ng-app="myApp">
<div data-ng-controller="MyController">
<my-directive data-ng-click="myFirstFunction('Hallo')"></my-directive>
<my-directive data-ng-click="mySecondFunction('Hi')"></my-directive>
</div>
</div>
Angular:
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
restrict: 'EA',
replace: true,
scope: {
eventHandler: '&ngClick'
},
template: '<div id="holder"><button data-ng-click="eventHandler()">Call own function</button></div>'
};
});
app.controller('MyController', ['$scope', function($scope) {
$scope.myFirstFunction = function(msg) {
alert(msg + '!!! first function call!');
};
$scope.mySecondFunction = function(msg) {
alert(msg + '!!! second function call!');
};
}]);
Edit
Check solution that I made in jsFiddler is that what you were looking for?
http://jsfiddle.net/migontech/3QRDt/1/

How/when to use ng-click to call a route?

Suppose you are using routes:
// bootstrap
myApp.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.when('/home', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
});
$routeProvider.when('/about', {
templateUrl: 'partials/about.html',
controller: 'AboutCtrl'
});
...
And in your html, you want to navigate to the about page when a button is clicked. One way would be
<a href="#/about">
... but it seems ng-click would be useful here too.
Is that assumption correct? That ng-click be used instead of anchor?
If so, how would that work? IE:
<div ng-click="/about">
Routes monitor the $location service and respond to changes in URL (typically through the hash). To "activate" a route, you simply change the URL. The easiest way to do that is with anchor tags.
Go Home
Go to About
Nothing more complicated is needed. If, however, you must do this from code, the proper way is by using the $location service:
$scope.go = function ( path ) {
$location.path( path );
};
Which, for example, a button could trigger:
<button ng-click="go('/home')"></button>
Here's a great tip that nobody mentioned. In the controller that the function is within, you need to include the location provider:
app.controller('SlideController', ['$scope', '$location',function($scope, $location){
$scope.goNext = function (hash) {
$location.path(hash);
}
;]);
<!--the code to call it from within the partial:---> <div ng-click='goNext("/page2")'>next page</div>
Using a custom attribute (implemented with a directive) is perhaps the cleanest way. Here's my version, based on #Josh and #sean's suggestions.
angular.module('mymodule', [])
// Click to navigate
// similar to <a href="#/partial"> but hash is not required,
// e.g. <div click-link="/partial">
.directive('clickLink', ['$location', function($location) {
return {
link: function(scope, element, attrs) {
element.on('click', function() {
scope.$apply(function() {
$location.path(attrs.clickLink);
});
});
}
}
}]);
It has some useful features, but I'm new to Angular so there's probably room for improvement.
Remember that if you use ng-click for routing you will not be able to right-click the element and choose 'open in new tab' or ctrl clicking the link. I try to use ng-href when in comes to navigation. ng-click is better to use on buttons for operations or visual effects like collapse.
But
About
I would not recommend. If you change the route you might need to change in a lot of placed in the application. Have a method returning the link. ex:
About. This method you place in a utility
I used ng-click directive to call a function, while requesting route templateUrl, to decide which <div> has to be show or hide inside route templateUrl page or for different scenarios.
AngularJS 1.6.9
Lets see an example, when in routing page, I need either the add <div> or the edit <div>, which I control using the parent controller models $scope.addProduct and $scope.editProduct boolean.
RoutingTesting.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testing</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-route.min.js"></script>
<script>
var app = angular.module("MyApp", ["ngRoute"]);
app.config(function($routeProvider){
$routeProvider
.when("/TestingPage", {
templateUrl: "TestingPage.html"
});
});
app.controller("HomeController", function($scope, $location){
$scope.init = function(){
$scope.addProduct = false;
$scope.editProduct = false;
}
$scope.productOperation = function(operationType, productId){
$scope.addProduct = false;
$scope.editProduct = false;
if(operationType === "add"){
$scope.addProduct = true;
console.log("Add productOperation requested...");
}else if(operationType === "edit"){
$scope.editProduct = true;
console.log("Edit productOperation requested : " + productId);
}
//*************** VERY IMPORTANT NOTE ***************
//comment this $location.path("..."); line, when using <a> anchor tags,
//only useful when <a> below given are commented, and using <input> controls
$location.path("TestingPage");
};
});
</script>
</head>
<body ng-app="MyApp" ng-controller="HomeController">
<div ng-init="init()">
<!-- Either use <a>anchor tag or input type=button -->
<!--Add Product-->
<!--<br><br>-->
<!--Edit Product-->
<input type="button" ng-click="productOperation('add', -1)" value="Add Product"/>
<br><br>
<input type="button" ng-click="productOperation('edit', 10)" value="Edit Product"/>
<pre>addProduct : {{addProduct}}</pre>
<pre>editProduct : {{editProduct}}</pre>
<ng-view></ng-view>
</div>
</body>
</html>
TestingPage.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.productOperation{
position:fixed;
top: 50%;
left: 50%;
width:30em;
height:18em;
margin-left: -15em; /*set to a negative number 1/2 of your width*/
margin-top: -9em; /*set to a negative number 1/2 of your height*/
border: 1px solid #ccc;
background: yellow;
}
</style>
</head>
<body>
<div class="productOperation" >
<div ng-show="addProduct">
<h2 >Add Product enabled</h2>
</div>
<div ng-show="editProduct">
<h2>Edit Product enabled</h2>
</div>
</div>
</body>
</html>
both pages -
RoutingTesting.html(parent), TestingPage.html(routing page) are in the same directory,
Hope this will help someone.
Another solution but without using ng-click which still works even for other tags than <a>:
<tr [routerLink]="['/about']">
This way you can also pass parameters to your route: https://stackoverflow.com/a/40045556/838494
(This is my first day with angular. Gentle feedback is welcome)
You can use:
<a ng-href="#/about">About</a>
If you want some dynamic variable inside href you can do like this way:
<a ng-href="{{link + 123}}">Link to 123</a>
Where link is Angular scope variable.
just do it as follows
in your html write:
<button ng-click="going()">goto</button>
And in your controller, add $state as follows:
.controller('homeCTRL', function($scope, **$state**) {
$scope.going = function(){
$state.go('your route');
}
})

Resources