In the below code, I'm trying to get a console log in the Directive (child scope),I need to get scope details.I tried adding a scope variable to the function in the directive also, but didn't work.
How can I fix this?
myDirective.html
<html ng-app="MyAppdr">
<head>
<script src="angular.js"></script>
<script src="appdr.js"></script>
</head>
<body ng-controller="dirCtrl">
<h1>hello</h1>
<employee-card></employee-card>
<!--div employee-card></div>
<div class="employee-card"></div--->
</body>
<html>
employee_info.html
<b>{{employee.name}}</b> - {{employee.job}}
<br/><br/>
<div ng-show='!!employee.followers'>
followers
<ul>
<li ng-repeat='name in employee.followers'>{{name}}</li>
</ul>
<button ng-click="follow('Galaa')">follow</button>
</div>
</div>
appdr.js
name="MyAppdr";
requires=[];
appdr=angular.module(name,requires);
appdr.controller("dirCtrl",function($scope){
console.log("This is controller dirCtrl");
$scope.employee={
name:"subo",
job:"cat",
followers:["chin","adyakshaka","aluu"]
}
console.log("parent ",$scope);
/*
$scope.follow=function(name){
$scope.employee.followers.push(name);
}
*/
});
appdr.directive("employeeCard",function(){
//$scope.employee={};
console.log("child ",$scope);
return{
templateUrl:'employee_info.html',
restrict:"AEC",
//replace:true,
controller:function($scope){
$scope.follow=function(name){
$scope.employee.followers.push(name);
}
},
scope:true
}
});
For your particular case, using scope: false seems to be sufficient if you are not showing multiple cards in same page.
appdr.directive("employeeCard",function() {
return {
scope: false,
// other attributes
If you need to show multiple cards in same page, use isolated scope and pass in
appdr.directive("employeeCard",function() {
return {
scope: {
employee: '='
},
// other attributes
<employee-card employee="employee"></employee-card>
Move the console.log() inside the controller of the directive.
appdr.directive("employeeCard", function() {
return {
templateUrl: 'employee_info.html',
restrict: "AEC",
//replace:true,
controller: function($scope) {
console.log("child ", $scope);
$scope.follow = function(name) {
$scope.employee.followers.push(name);
}
},
scope: true
}
});
If you will have only one employee card on the page then keep scope: true else if you need to show multiple cards in the same page, use an isolated scope and pass it in the template.
appdr.directive("employeeCard", function() {
return {
templateUrl: 'employee_info.html',
restrict: "AEC",
//replace:true,
controller: function($scope) {
console.log("child ", $scope);
$scope.follow = function(name) {
$scope.employee.followers.push(name);
}
},
scope: {
employee: "="
}
}
});
And in the html use something like
<employee-card employee="employee"></employee-card>
Refer the documentation of directive here
Related
A vue.js component creates a button which should call a function, but the function is never called and the v-on:click is not visible in Chrome's element inspect. My html goes like this:
<bottomcontent></bottomcontent>
And my Vue is like this:
var bottomcontent = {
template: '<div class="bottomcontent"><div class="moreresults" v-on:click="appendcontent">More Results</div></div>'
}
new Vue({
el : 'body',
data : {
homepage:{
numberofdivs: 60
}
},
methods : {
appendcontent: function() {
homepage.numberofdivs += 60
}
},
components: {
'bottomcontent': bottomcontent
}
})
The problem is that methods has to use funcions, not objects.
methods: {
appendcontent: function() {
homepage.numberofdivs += 60
}
}
You also have to correct your markup accordingly.
var bottomcontent = {
template: '<div class="bottomcontent"> <div class="moreresults" v-on:click="appendcontent"> More Results </div></div>'
}
There are some problems lead to the crack.
In the function appendcontent,you should call the data "this.homepage.numberofdivs".
and the correct demo is posted on https://jsfiddle.net/atsknydr/
methods : {
appendcontent: function() {
this.homepage.numberofdivs += 60;
console.log(this.homepage.numberofdivs);
}
}
First, as the warning says:
[Vue warn]: Do not mount Vue to <html> or <body> - mount to normal elements instead.
So, you should create an element like <div id="app"></div> to mount your app instead of <body>.
The problem you are facing is a scope problem. You are trying to call a method from the inside a component scope, that is why it's not finding the method.
Take a look at the docs to understand better.
So, in order to make this work you should change the method from the app scope to the template scope.
Your html:
<body>
<div id="app">
<bottomcontent></bottomcontent>
</div>
</body>
Your js:
<script>
var bottomcontent = {
template: '<div class="bottomcontent"><div class="moreresults" v-on:click="appendcontent">More Results</div></div>',
data: function () {
return {
homepage: {
numberofdivs: 60
}
}
},
methods: {
appendcontent: function () {
console.log('Called method!');
this.homepage.numberofdivs += 60
}
}
}
new Vue({
el: '#app',
components: {
'bottomcontent': bottomcontent
}
})
</script>
In my angular js Application, I have a directive inside a ng-repeat. Directive has a template in which the HTML part is loaded. Inside that template I am declaring a ui-sref Router dynamically setting states!
This does not Work!
I have tried a Fiddle
Without using a Directive ui-sref works Fine. But I need it in Directive's template.
MY HTML PART
<div ng-repeat="sp in obj.PEs">
<div draw-pe proc="{{sp.peId}}"></div>
</div>
<div style="border:1px;" ui-view="properties"></div>
My Script Part
var myApp = angular.module('myApp', ["ui.router"]);
myApp.controller("testCtrl", function($scope) {
$scope.obj = {
"PEs": {
"1": {
"peId": "1",
"peName": "Exp1",
"peDisplayName": "Exp",
"peType": "Exp",
"peCategory": "PE"
},
"2": {
"peId": "2",
"peName": "RN1",
"peDisplayName": "RNull",
"peType": "RN",
"peCategory": "PE"
}
}
}
})
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('Exp', {
url: '/Exp/:peId',
views: {
"properties": {
template: ".<h3>I am Exp ! </h3>",
controller: function($scope, $stateParams) {
var peId = $stateParams.peId;
alert("Peid-> " + angular.toJson($scope.obj.PEs[peId]));
}
}
}
})
.state('RN', {
url: '/RN/:peId',
views: {
"properties": {
template: "<h3> I am RN ! </h3>",
controller: function($scope, $stateParams) {
var peId = $stateParams.peId;
alert("Peid-> " + angular.toJson($scope.obj.PEs[peId]));
}
}
}
})
});
myApp.directive("drawPe", function() {
return {
restrict: "AE",
template: '<div ui-sref="{{peObj.peType}}( { peId:peObj.peId } )"> <h5>{{peObj.peDisplayName}}</h5></div>',
link: function($scope, element, attrs) {
var procId = $scope.$eval(attrs.proc);
alert(procId);
// alert(angular.toJson(scope.obj.processElements[procId]))
$scope.peObj = $scope.obj.PEs[procId];
}
}
})
See the Browser Console, on clicking the output Part!
ERROR
Error: Invalid state ref '( { peId:peObj.peId } )'
What will be the best Practice to call dynamic state names inside directives Template? I Have read some previous asked question and answer, But I am not clear with the idea as I am new to Angular Js.
Any Idea/help appreciated
Thanks
You can use $compile service to compile your directive's template when your scope changes.
Your directive could look like this:
myApp.directive("drawPe", function($compile) {
return {
restrict: "AE",
tranclude: true,
scope: {
peObj: '='
},
template: ' <h5>{{peObj.peDisplayName}}</h5>',
link: function(scope, element, attrs) {
console.log(scope.peObj);
scope.$watch(
function(scope) {
// watch the 'compile' expression for changes
//return scope.$eval(attrs.compile);
},
function(value) {
$compile(element.contents())(scope);
}
);
}
}
});
And your html:
<div ng-repeat="sp in obj.PEs">
<div draw-pe pe-obj="sp" proc="{{sp.peId}}"></div>
</div>
<div style="border:1px;" ui-view="properties"></div>
Working fiddle is here.
I have a view with a ui.bootstrap modal that has its own controller.
In the view, i have a directive that generates a number of buttons with a unique ID.
I want to be able to click on one of the buttons generated and call the main view's controller to launch the modal.
Here is the main view module:
/* global angular */
angular.module('my.jobs', [
'ui.router',
'ui.bootstrap'
])
.controller('DashboardJobsCtrl', function DashboardJobsController($rootScope, $scope, $log, $state, $modal) {
var self = this;
angular.extend(this, {
displayReceipt: function(jobId) {
var modalInstance = $modal.open({
animation: true,
templateUrl: 'receiptModal.html',
size: 'lg',
controller: function($scope, $modalInstance, jobsService) {
//CODE HERE FOR ADDING VALUES TO THE MODAL...
$scope.clear = function() {
$modalInstance.close();
};
}
});
}
});
});
Here is the directive:
angular.module('jobView', ['ui.router', 'ui.bootstrap'])
.directive('jobView', function($compile, $http, $templateCache, DOMAINS) {
return {
restrict: 'E',
scope: {
job: '=',
view: '#'
},
template: 'myTemplate.html',
link: function($scope, element, attrs) {
//ASSUME THERE IS CODE HERE FOR GENERATING UNIQUE ID FOR JOBS
//NEXT LINE I WANT TO CALL MODAL FROM THE MAIN VIEW MODULE
$scope.displayReceipt('jobId')
}
};
});
I know this is a simple scope issue, but it's driving me nuts that I can't make the connection.
Here is the perfect example. calling method of parent controller from a directive in AngularJS.
I have update your example below.
<job-View updateParent='displayReceipt()'></job-View>
angular.module('jobView', ['ui.router', 'ui.bootstrap'])
.directive('jobView', function($compile, $http, $templateCache, DOMAINS) {
return {
restrict: 'E',
scope: {
job: '=',
view: '#',
updateParent:'&'
},
template: 'myTemplate.html',
link: function($scope, element, attrs) {
//ASSUME THERE IS CODE HERE FOR GENERATING UNIQUE ID FOR JOBS
//NEXT LINE I WANT TO CALL MODAL FROM THE MAIN VIEW MODULE
$scope.displayReceipt('jobId')
}
};
});
I have a directive
configModule.directive('iMemoryDiv',function () {
return {
restrict: 'E',
scope: {},
replace: true,
templateUrl: '/memoryDiv.html',
link: function(scope, el, attrs) {
scope.iObj = scope.$parent[attrs.bIObject];
if(angular.isDefined(scope.iObj)){
getSummary(scope.iObj);
}
function getSummary(iObj){
}
}
};
}
);
and I am calling it from html by passing an object attribute
<i-memory-div b-i-object="app"></i-memory-div> //here app is declared in a respective controller
but, here directive is getting loaded before the controller where value for 'app' is getting assigned.So scope.iObj = scope.$parent[attrs.bIObject] is always giving me undefined.
How can make directive load after the app value is getting assigned ??
Isn't it easier doing it this way:
configModule.directive('iMemoryDiv',function () {
return {
restrict: 'E',
scope: {
'bIObject': '=',
'getParentObject': '&'
},
replace: true,
templateUrl: '/memoryDiv.html',
link: function(scope, el, attrs) {
scope.$watch('bIObject', function(newValue) {
if(angular.isDefined(newValue)) {
getSummary(scope.getParentObject({name: newValue}));
}
});
function getSummary(iObj){
}
}
};
}
Or do you need more from the parent scope??
You could give your directive an isolated scope and add bIObject as a scope property:
scope: {
bIObject: '=',
},
you could then put your code in the controller: rather than link:
Use $observe service in link function,like this
if(attrs. bIObject) {
attrs.$observe('bIObject', function(value) {
console.log(value);
})
}
I have an MVC application using angularJS. I have a primary navigation and secondary navigation. I am using ngRoute for primary navigation. I made secondary navigation template a directive that I can use in all the other pages. The template used in the directive needs some input parameters.
Routing code:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/SecondaryNavigation/1', {
templateUrl: 'administration/Page1',
resolve: {
SecNavItems: ["$http", function($http){
var navItems = $http.get('/Navigation/SecondaryNavigation', {params: { pageName: 'Administration'}});
navItems.success(function (data) {
return data;
});
}]
},
controller: 'AdminController'
})}]);
var AdminController = function ($scope, SecNavItems) {
$scope.secList = SecNavItems;
}
AdminController.$inject = ["$scope", "SecNavItems"];
myApp.controller("AdminController", AdminController);
Web method code:
[HttpGet]
public JsonResult SecondaryNavigation(string pageName)
{
Dictionary<string, string> secnavItems = new Dictionary<string, string>();
secnavItems.Add("1", "Item1");
secnavItems.Add("2", "Item2");
var navigationItemsJson = Json(secnavItems, JsonRequestBehavior.AllowGet);
return navigationItemsJson;
}
Page1 code is
<secondary-navigation></secondary-navigation>
My directive is defined as follows:
myApp.directive("secondaryNavigation", function () {
return {
restrict: 'E',
scope: {},
templateUrl: '/navigation/secondaryNavigation'
}
});
Partial view template:
<div style="height:100%; width:25%; background-color:#675c5c; color: white; float:left">
#foreach (KeyValuePair<int, string> navItem in secList)
{
#navItem.Value<br /><br />
}
</div>
<div style="height:100%; width:75%; float:right"></div>
When I run the application I do not see the Item1 and Item2 in the page instead I see {{object}}
Please advise what I am missing in passing the parameters to the template used in the directive.
Thank you.
Figured what went wrong.
I had to create a html template of secondary navigation. I then included the web service call in the admincontroller, set the object value to the webservice result and added it to the routeProvider. I then
set the scope to false in the directive.
Following are the changes I made.
Routing code:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/SecondaryNavigation/1', {
templateUrl: 'administration/Page1',
controller: 'AdminController'
})}]);
var AdminController = function ($scope, $http) {
var navItems = $http.get('/Navigation/SecondaryNavigation', {params: { pageName: 'Administration'}});
navItems.success(function (data) {
$scope.secList = data;
});
}]
},
}
AdminController.$inject = ["$scope", "$http"];
myApp.controller("AdminController", AdminController);
My directive is defined as follows:
myApp.directive("secondaryNavigation", function () {
return {
restrict: 'E',
scope: false,
templateUrl: '/navigation/secondaryNavigation'
}
});