Reputation: 8079
I've got two components:
<cmp-one></cmp-one>
is inserted to the DOM, while I'm using $compile
to create a <cmp-top>
.
Then in cmpTop
controller I need to get <cmp-one>
and insert it into the <cmp-top>
.
Insertion works fine, but I need to access cmpTop
controller methods from cmpOne
- and can't figure out how.
What I've tried so far is adding require: {cmpTop: '^^'}
- not working since there is no parent component before insertion is done.
So, how can I achieve this? I mean - insert some component into another, and share its methods to the added child.
updated
Here is the plunker: http://plnkr.co/edit/mgwC5Mbh5qid5q5ELDdQ?p=info
So, I need to access PanelController
's methods from the DialogComponentController
.
Or, maybe I'm doing it all wrong - so please give me a clue how to make it properly.
Upvotes: 0
Views: 262
Reputation: 1794
Check this working example.
var app = angular.module('plunker', []);
PanelController.$inject = ['$element'];
function PanelController($element) {
var $ctrl = this;
$ctrl.showAlert = function () {
alert('Message from PanelController');
};
$ctrl.close = function () {
// $element.remove();
};
$ctrl.onShow = function () {
};
$ctrl.$onInit = $onInit;
$ctrl.$onDestroy = $onDestroy;
function $onInit() {
var srcEl = angular.element(document.querySelector($ctrl.source));
srcEl.attr('panel', '$ctrl');
$element
.find('.panel')
.append(srcEl
.css('display', 'block')
);
$ctrl.onShow();
var bodyRect = document.body.getBoundingClientRect(),
elRect = $element[0].getBoundingClientRect(),
position = {
left: '',
top: '',
right: '',
bottom: ''
};
position.top = (bodyRect.height - elRect.height) / 4; //eslint-disable-line no-magic-numbers
position.left = (bodyRect.width - elRect.width) / 2; //eslint-disable-line no-magic-numbers
$element.css('top', position.top + 'px');
$element.css('left', position.left + 'px');
}
function $onDestroy() {
}
}
function DialogComponentController() {
var $ctrl = this;
$ctrl.callPanelMethod = function () {
var scope = angular.element($('ccm-panel div')).scope();
scope.$ctrl.showAlert();
}
$ctrl.actions = {
close: function (event, button) {
event.preventDefault();
event.stopPropagation();
$ctrl.instance.hide(button);
}
};
$ctrl.$onInit = $onInit;
$ctrl.$onDestroy = $onDestroy;
$ctrl.$onChanges = function () {
};
function $onInit() {
}
function $onDestroy() {
}
}
app.component('ccmDialog', {
template: '<div style="border: 1px solid green; margin: 5px" >dialog <button ng-click="$ctrl.callPanelMethod()">click here to get alert from controll PanelController </button></div>',
controller: DialogComponentController,
bindings: {
panel: '<',
panelShown: '&'
}
});
app.component('ccmPanel', {
template: '<div>' +
'<div style="border: 1px solid red" class="panel" ng-click="$ctrl.close()">panel</div>' +
'</div>',
controller: PanelController,
bindings: {
source: '='
}
});
app.controller('MainCtrl', function ($rootScope, $scope, $compile) {
$scope.name = 'World';
$scope.open = function (source, target) {
var scope = $rootScope.$new();
scope.$ctrl = {
source: source
};
var el = $compile('<ccm-panel source="$ctrl.source" style="position: absolute;"></ccm-panel>')(scope);
angular.element(document.querySelector(target)).append(el);
}
});
<script data-require="[email protected]" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<button ng-click="open('ccm-dialog', 'body')">open dialog</button>
<ccm-dialog panel="test" style="display: none"></ccm-dialog>
</div>
Upvotes: 0
Reputation: 5344
$element
.find('.panel')
.append(srcEl
.css('display', 'block')
);
You use .find
here with a class selector, but according to the documentation, angular just supports tag selector.
According to the documentation
Components only control their own View and Data: Components should never modify any data or DOM that is out of their own scope. Normally, in AngularJS it is possible to modify data anywhere in the application through scope inheritance and watches. This is practical, but can also lead to problems when it is not clear which part of the application is responsible for modifying the data. That is why component directives use an isolate scope, so a whole class of scope manipulation is not possible.
@K Scandrett's answer is great and may be the best practice, but my favorite solution is:
In DialogComponentController:
$rootScope.$emit("abc");
In PanelController:
$rootScope.$on("abc",function(){
console.log("got it");
//and do whatever you want
});
Upvotes: 0
Reputation: 16540
You can use a common Service to communicate between them (as playerone mentioned).
app.controller('mainController', function($scope, menuSelection) {
$scope.menuSelection = menuSelection; // retrieve settings object from service method and bring into scope
// now whenever one sets $scope.menuSelection.selected = "object 2", it will update the value in the other controller as well (and vice-versa)
});
app.controller('secondController', function($scope, menuSelection) {
$scope.menuSelection = menuSelection; // retrieve settings object from service method and bring into scope
});
app.factory('menuSelection', function() {
var settings = {};
settings.selected = 'Object 1'; // default
return settings;
});
You can point $scope.menuSelection.myFooFunction = ...
to a function in one directive and call it from another.
Upvotes: 1