I am getting a value from a function in controller1. I want to set this value to controller2's directive's template. I am confused on how to use scope in this to achieve the same.
Html
<body ng-app = "myApp" ng-controller="parentcontroller as ctrl">
<div class ="boardcanvas" style ="overflow-x:auto;">
<div id = "board">
<list-wrapper ng-repeat="task in ctrl.tasks track by $index" class ="listwrapper" id = "listwrapper"></list-wrapper>
<add-list-controls class = "controls" tasks ="ctrl.tasks" ng-show ="ctrl.listcontrolarea"></add-list-controls>
</div>
</div>
</body>
Controller1 and its Directive:
angular.module('myApp')
.controller('listController', ['$scope','$compile','$http', function($scope, $compile, $http){
'ngInject';
$scope.tasks=[];
$scope.cardarr =[];
vm.addme = function(){
console.log(vm);
console.log($scope.tasks);
$scope.tasks.push({title: $scope.title, cardarr: []});
}
}])
.directive('addListControls', function() {
return {
restrict: 'E', // Element directive'
controller: 'listController as listctrl2',
scope: { tasks: "=",
cardarr: "="},
template: `<textarea ng-model= "listctrl2.title" placeholder ="Add a List" id="input" style = "position:absolute"></textarea>
<button id="controlbutton" class ="btn btn success" style = "position:absolute" ng-click="listctrl2.addme()">Save
</button>`,
};
});
Controller2 and its Directive:
.controller('listWrapperController', ['$scope','$compile','$http', function($scope, $compile, $http){
'ngInject';
$scope.tasks=[];
}])
.directive('listWrapper', function() {
return {
restrict: 'E', // Element directive
scope:{
tasks: '='
},
controller: 'listWrapperController as listctrl',
template: `<div id="titlebox">
<b class ="card1" tasks="listctrl.task" id ="cardtitle">
{{task.title}} // set the value from controller1 here
</b>
</div> `
};
});
You are initalizing the $scope.tasks array on both controllersand this override the original $scope.task reference (ctrl.tasks) that is set by directive definititon.
Try comment or initialize only if undefined
$scope.tasks= $scope.tasks || [];
$scope.cardarr = $scope.cardarr || [];
The listWrapper directive must be changed andd translate the ng-repeat to its template:
HTML
<list-wrapper tasks="ctrl.tasks"></list-wrapper>
listWrapper directive
(...)
.directive('listWrapper', function() {
return {
restrict: 'E', // Element directive
scope:{
tasks: '='
},
controller: 'listWrapperController as listctrl',
template:
`<div id="titlebox" ng-repeat="task in tasks track by $index" class ="listwrapper" id = "listwrapper">
<b class ="card1" id ="cardtitle">
{{task.title}} // set the value from controller1 here
</b>
</div> `
};
});
Related
I have two controllers: One with controls - textarea and button. And another that takes the value of the text from the textarea and then displays it. I am able push the value of the textarea into an array. But I cant access the array in another directive so that it wud display the value.
I am new to angular scopes.
First Controller:
This directive has its own controller.
angular.module('myApp')
.controller('listController', ['$scope','$compile','$http', function($scope, $compile, $http){
'ngInject';
var vm =this;
console.log("in addmectrl");
$scope.tasks=[];
$scope.cardarr =[];
vm.addme = function(){
$scope.tasks.push({title: vm.title, cardarr: []}); //pushes in to an array
}
}])
.directive('addListControls', function() {
return {
restrict: 'E', // Element directive'
controller: 'listController as listctrl2',
scope: { tasks: "#",
cardarr: "#"},
template: `
<textarea ng-model= "listctrl2.title" placeholder ="Add a List"
id="input" style = "position:absolute">
</textarea>
<button id="controlbutton" class ="btn btn success"
style = "position:absolute"
ng-click="listctrl2.addme()">Save
</button>
<img id ="remove" src ="remove.png"
ng-click ="listctrl2.removeinput()">`,
};
});
This directive accesses the parent controller.
Display the text in this template---
angular.module('myApp')
.directive('listWrapperTitlebox', function() {
return {
restrict: 'E', // Element directive
template: `
<b class ="card1" id ="cardtitle">{{task.title}}</b>
<a class ="card1" tabindex="0" data-trigger ="focus"
data-toggle="popover"
ng-click = "ctrl.listpopover($index)" >...</a>`
};
});
I am use to working in Angular and now I am on AngularJS ( The otherway round)
I've a directive:
<li ng-mouseover="vm.setCurrentEditedTile(item.id)">
<panel-buttons-directive ></panel-buttons-directive>
</li>
My panel-buttons-directive has a controller called ButtonsController.
What I would like when user hovers on top of <li> element, it run a function that is inside the child controller. So that I have a separate "Module" where I have buttons HTML in the directive and function in the controller and from the parent I can call the function.
Link: https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md
One approach is to have the directive publish an API when initialized:
<fieldset ng-mouseover="pbdAPI.setCurrentEditedTile(item.id)">
Mouseover Me
</fieldset>
<panel-buttons-directive on-init="pbdAPI=$API">
</panel-buttons-directive>
app.directive("panelButtonsDirective", function() {
return {
scope: { onInit: '&' },
bindToController: true,
controller: ButtonsController,
controllerAs: '$ctrl',
template: `<h3>Panel Buttons Component</h3>
<p>Current edited tile = {{$ctrl.id}}</p>
`,
};
function ButtonsController() {
var $ctrl = this;
var API = { setCurrentEditedTile: setCurrentEditedTile };
this.$onInit = function() {
this.onInit({$API: API});
};
function setCurrentEditedTile(id) {
$ctrl.id = id;
}
}
})
The directive in the above example uses expression & binding to publish its API when initialized.
The DEMO
angular.module("app",[])
.directive("panelButtonsDirective", function() {
return {
scope: { onInit: '&' },
bindToController: true,
controller: ButtonsController,
controllerAs: '$ctrl',
template: `<h3>Panel Buttons Component</h3>
<p>Current edited tile = {{$ctrl.id}}</p>
`,
};
function ButtonsController() {
var $ctrl = this;
var API = { setCurrentEditedTile: setCurrentEditedTile };
this.$onInit = function() {
this.onInit({$API: API});
};
function setCurrentEditedTile(id) {
$ctrl.id = id;
}
}
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h3>Mouseover Component DEMO</h3>
<p><input ng-model="item.id" ng-init="item.id='tile0'"/></p>
<fieldset ng-mouseover="pbdAPI.setCurrentEditedTile(item.id)">
Mouseover Me
</fieldset>
<panel-buttons-directive on-init="pbdAPI=$API">
</panel-buttons-directive>
</body>
I have this simple code of my directive:
app.directive('ngModal', function ($parse) {
return {
restrict: 'E',
template: document.getElementById('ng-modal').innerHTML,
replace: true,
controller : "#",
name:"controllerName",
}
})
<ng-modal controller-name="ModalCtrl"></ng-modal>
And this is my controller:
app.controller('ModalCtrl', ['$scope', function ($scope) {
$scope.model = 'default text'
}])
<div ng-controller="ModalCtrl">
<input type="text" ng-model="model">
</div>
I want, that model field inside my Directive will updated automatically. But I see "default text" always inside directive and changed inside controller. How can I bind it?
You have to add a service to keep information between controllers. Controllers are always created per "view" so your ng-modal and div have different controllers in use, this is why model data is not updated between them.
Fast example:
app.service('sharedData', function() {
var sharedData = {
field: 'default text'
};
return sharedData;
});
app.directive('ngModal', function () {
return {
restrict: 'E',
template: '',
replace: true,
controller : "#",
name:"controllerName",
}
});
app.controller('ModalCtrl', ['$scope', 'sharedData', function ($scope, sharedData) {
$scope.model = sharedData;
}]);
<ng-modal controller-name="ModalCtrl">{{model.field}}</ng-modal>
<div ng-controller="ModalCtrl">
<input type="text" ng-model="model.field">
</div>
In this plunker, I am trying to apply the currency filter to the display that is not being edited. It is an edit in place directive that displays an input when it is active but I want the filter applied when it is not active.
script:
var app = angular.module('plunker', []);
app.directive('editInPlace', function () {
return {
restrict: 'E',
scope: {
value: '='
},
template: '<span ng-click="edit()" ng-bind="value" ng-show="!editing"></span><input ng-model="value" ng-blur="onBlur()" ng-show="editing"></input>',
link: function ($scope, element, attrs) {
var inputElement = element.find('input');
// reference the input element
element.addClass('edit-in-place');
// Initially, we're not editing.
$scope.editing = false;
// ng-click handler to activate edit-in-place
$scope.edit = function () {
$scope.editing = true;
// element not visible until digest complete
// timeout causes this to run after digest
setTimeout(function() {
inputElement[0].focus();
});
};
$scope.onBlur = function() {
$scope.editing = false;
};
}
};
});
app.controller('MainCtrl', function($scope) {
$scope.contacts = [
{name: 'Katniss', total: 35645.58},
{name: 'Peeta', total: 25178.21}
];
});
view:
<body ng-controller="MainCtrl">
<ul style="margin-top:20px;">
<li ng-repeat="contact in contacts">
{{contact.name}} --
<edit-in-place value="contact.total"></edit-in-place>
</li>
</ul>
<hr/>
<pre>{{contacts}}</pre>
<hr/>
</body>
You use the filter the same way you would use it in any other template:
template: '<span ng-click="edit()" ng-show="!editing">{{ value | currency}}</span><input ng-model="value" ng-blur="onBlur()" ng-show="editing"></input>'
Here's your modified plunkr.
I would like the ng-click to change the value of the controller scope variable 'controllerLabel'. What's the best way of achieving this without using a controller scope function?
HTML:
<div ng-app="app">
<div ng-controller="Ctrl">
<p>{{controllerLabel}}</p>
<my-template></my-template>
</div>
<!-- my-template.html -->
<script type="text/ng-template" id="my-template.html">
<div ng-repeat="clickLabel in clickLabels">
<label ng-click="controllerLabel = {{clickLabel.text}}">{{clickLabel.text}}</label>
</div>
</script>
</div>
JavaScript:
angular.module('app', [])
.controller('Ctrl', function Ctrl1($scope) {
$scope.controllerLabel = 'Default text';
$scope.clickLabels = [
{'text':'Hello'},
{'text':'World'},
];
})
.directive('myTemplate', function() {
return {
restrict: 'E',
templateUrl: 'my-template.html'
};
});
JSFiddle
You can add link to directive and write like:
.directive('myTemplate', function() {
return {
restrict: 'E',
link: function (scope) {
scope.onClick = function (clickLabel) {
scope.controllerLabel = clickLabel.text;
}
},
templateUrl: 'my-template.html'
};
});
HTML
<script type="text/ng-template" id="my-template.html">
<div ng-repeat="clickLabel in clickLabels">
<label ng-click="onClick(clickLabel)">{{clickLabel.text}}</label>
</div>
</script>
Actually you can write like #Alborz posted but I think to add method into link and call from HTML will be clearer and easy to debug.
Demo Fiddle
I updated your fiddle;
Updated fiddle
You need to use controllerLabel as an object property to have a shared object with controller.
angular.module('app', [])
.controller('Ctrl', function Ctrl1($scope) {
$scope.label = {};
$scope.label.controllerLabel = 'Default text';
$scope.clickLabels = [
{'text':'Hello'},
{'text':'World'},
];
})
.directive('myTemplate', function() {
return {
restrict: 'E',
templateUrl: 'my-template.html'
};
});
Template:
Note to label.controllerLabel = clickLabel.text
<div ng-repeat="clickLabel in clickLabels">
<label ng-click="label.controllerLabel = clickLabel.text">{{clickLabel.text}}</label>
</div>