AngularJS (1.5) detach panel to child window and vice versa - angularjs

I have a child controller which I can use inside some main controller. For example, it's a panel inside the main page controller. Now I need to open a child window with this child controller inside. How can I do this?
For example, I have a video player panel and I want it to become detachable and scalable in size.
My child controller has its own template-file and I inject it to the main controller with this:
...
<div class="col-sm-6 col-md-6">
<span ng-include="AVTemplateUrl" ng-controller="VideoCtrl as AV" data-ng-init="AV.init()"></span>
</div>
...
and contructor for the child:
angular.module('myApp.video', ['ngRoute'])
.controller('VideoCtrl', ['$scope', ...],
function ($scope, ...) {
$scope.AVTemplateUrl = 'view/device/video.html';
let AV = $scope.AV = { ... }
...
P.S. sorry for my English.

Found the solution here https://stackoverflow.com/a/17066146/2982280 and here http://embed.plnkr.co/dz1A1h/
Parent controller:
.controller(
...
let model = $scope.model = {
detach() {
// remove the controller panel from dom
},
maximize() {
// detach panel to a new child window
this.detach();
window.$windowScope = $scope; // $scope contains 'model' field
$window.open('_child_window_url_', '_child_window_name_', 'menubar=no,location=no,resizable=yes,scrollbars=no,status=no - window params');
},
onClick() {
// some DOM handler - button click, for example
},
...
};
...
);
Child controller:
1) use router:
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('_child_window_url_', {
templateUrl: '_template_file_path_',
controller: '_child_controller_name_'
});
}])
2) implement the DOM handlers to make them call the parent's handlers:
onClick: function () {
window.opener.$windowScope.model.onClick();
},

Related

$uibModal templateUrl does not change modal content

all!
I'm making an angular application and want to implement a simple modal window popup, that will allow users to "construct" a URL.
My page looks like this:
Here's the HTML of the URL button (third in row) that is to trigger my button.
<button class="btn btn-secondary" ng-click="vm.showUrlModal()" id="button-url-to-modal" type="button" title="Hyperlink <a> Ctrl+L"><img src="/images/url.png" height="18px"/></button>
The controller that handles the page looks like this:
(function() {
function postchallengeController($uibModal, newChallengeData) {
var vm = this;
vm.message = "Post a challenge!";
vm.showUrlModal = function() {
$uibModal.open({
templateUrl: '/url_modal/url_modal.view.html',
controller: 'url_modal',
controllerAs: 'vm',
})
}
postchallengeController.$inject = ['$uibModal', 'newChallengeData'];
/* global angular */
angular
.module('stackunderflow')
.controller('postchallengeController', postchallengeController);
})();
And the referenced url_modal controller:
(function() {
function url_modal($uibModalInstance) {
var vm = this;
vm.modal = {
cancel: function() {
$uibModalInstance.close();
}
};
}
url_modal.$inject = ['$uibModalInstance'];
/* global angular */
angular
.module('stackunderflow')
.controller('url_modal', url_modal);
})();
In the referenced document (/url_modal/url_modal.view.html) is a simple Hello World, that should be displayed when I open the modal - however, when I do so, the page opens a modal with the current content overlayed on top of it.
See here :
What could I be doing wrong?
Thank you!
EDIT: I do have both controllers referenced in my index.html and my module does contain ['ui.bootstrap']
The error might be hidden in the reference of the html file.
Make sure that the parent directory of the /url_modal/ directory is set as the root folder you set with express.static function call.

How to invoke a function in parent component from nested child component in Angular 1x

I have a parent component say purchaseComponent and a child component say supplierComponent. Supplier component works independently when I load it in a full view. Also I am successfully loading the supplierComponent in a modal inside purchaseComponent.
What I need is when I click addSupplier button which is in supplierComponent it should complete its current functionality and then call hide method from purchaseComponent.
supplierComponent
angular.module('TestApp').component('addsupplierComponent', {
templateUrl: 'addsuppliercomponent/addsupplier.html',
controller: AddsupplierController,
controllerAs: 'addsupplierCtrl'
});
function AddsupplierController(){
var vm = this;
vm.addSupplier = addSupplier;
function addSupplier(){
console.log("supplier component")
}
}
purchaseComponent
angular.module('TestApp').component('purchaseComponent', {
templateUrl: 'purchasecomponent/purchase.html',
controller: PurchaseController,
controllerAs: 'purchaseCtrl'
});
function PurchaseController(ProductService, LogService){
var vm = this;
vm.hideModal = hideModal;
function hideModal(){
console.log("Hide Modal")
}
}
purchase.html
<div class="modal-body">
<div class="card-content table-responsive">
<addsupplier-component></addsupplier-component>
</div>
</div>
Result I need: once I click addSupplier from purchaseComponent, output should be
Supplier component
Hide Modal
will [child]Component work independently without passing any parameter? coz I want this to work as an independent component too
To have the child component able to function independently, make the expression & binding optional with &? and check before invoking:
Child Component
app.component('childComponent', {
templateUrl: 'component/child.html',
controller: ChildController,
controllerAs: 'childCtrl',
bindings: {
onDone: '&?'
}
});
function ChildController(){
var vm = this;
vm.done = function done(){
console.log("child function")
vm.onDone && vm.onDone();
}
}
Parent Component
app.component('parentComponent', {
templateUrl: 'component/parent.html',
controller: ParentController,
controllerAs: 'parentCtrl'
});
function ParentController(ProductService, LogService){
var vm = this;
vm.hideModal = hideModal;
function hideModal(){
console.log("Hide Modal")
}
}
parent.html
<div class="modal-body">
<div class="card-content table-responsive">
<child-component on-done="parentCtrl.hideModal()">
</child-component>
</div>
</div>
By using optional expression &? binding, the child component can operate independently:
<child-component></child-component>
From the Docs:
All 4 kinds of bindings (#, =, <, and &) can be made optional by adding ? to the expression. The marker must come after the mode and before the attribute name. This is useful to refine the interface directives provide.
— AngularJS Comprehensive Directive API Reference - scope
You have to pass the hide function in the component bindings
Check the docs here
addsupplierComponent
angular.module('TestApp').component('addsupplierComponent', {
templateUrl: 'addsuppliercomponent/addsupplier.html',
controller: AddsupplierController,
controllerAs: 'addsupplierCtrl',
bindings: {
hideModal: '&'
}
});
function AddsupplierController(){
var vm = this;
vm.addSupplier = addSupplier;
function addSupplier(){
vm.hideModal()
}
}
purchase.html
<div class="modal-body">
<div class="card-content table-responsive">
<addsupplier-component hide-modal="purchaseCtrl.hideModal()"></addsupplier-component>
</div>
</div>

Angularjs 1.5 Nested Components bindings

am trying to pass a value from a parent-component to his nested child-component in angular 1.5
The value can be updated from the parents, but child cannot edit it, just show it. So is a one-way binding '<' right ?
And i cannot pass the child component right in the parent component declaration, because the parent component would have other uses too.
The point is my parent-component have common data stored, but them
children gonna use it in different ways.
And the parent-component gonna be used multiples times, with different
children, thats why i cannot pass the children inside parent
declaration. I need to bind the info, for auto updates purposes, when
parents updates the data, must be reflected by the children
HTML
<parent-component ng-transclude>
<child-component name="$ctrl.characters.arya"></child-component>
<child-component name="$ctrl.characters.john"></child-component>
</parent-component>
JS
// Parent Component declaration
// /////////////////////////
(function() {
'use strict';
angular
.module('app')
.component("parentComponent", {
transclude: true,
controller: "ParentComponentController",
template:
'<div class="parent-c"></div>'
});
})();
// Parent Component Controller
// /////////////////////////
(function() {
'use strict';
angular
.module('app')
.controller('ParentComponentController', ParentComponentController);
function ParentComponentController() {
var $ctrl = this;
$ctrl.characters = {};
$ctrl.characters.arya = "Arya Stark";
$ctrl.characters.john = "John Snow";
}
})();
//CHILD Component declaration
// /////////////////////////
(function() {
'use strict';
angular
.module('app')
.component("childComponent", {
bindings: {
name: '<'
},
controller: "ChildComponentController",
template:
'<div class="child-c"' +
'<h3>Im a child Component</h3>' +
'<p><strong>Name: </strong>{{$ctrl.name}}</p>' +
'</div>'
});
})();
// CHILD Component Controller
// /////////////////////////
(function() {
'use strict';
angular
.module('app')
.controller('ChildComponentController', ChildComponentController);
function ChildComponentController() {
var $ctrl = this;
}
})();
Check the WORKING SAMPLE on plunkr
The require attribute is for components communication, but i'm trying to use it with no success :(, need a piece of light here.
you have to use : <child-component name="$parent.$ctrl.characters.arya"></child-component>to pass a value from a parent-component to his nested child-component
There are different issues with your code:
function ParentComponentController() {
var $ctrl = this;
$ctrl.characters = {};
$ctrl.characters.arya = "Arya Stark";
$ctrl.characters.john = "John Snow";
}
You don't need to define a local variable for this since not changing context anywhere.
controller: "ParentComponentController",
Don't pass a string to this property, pass a reference:
controller: ParentComponentController,
Then if you want to pass name through the parent controller with require in the child component:
require: { parent: '^^parentComponent' },
Now that you have the parent controller bound to child you can use it with:
{{$ctrl.parent.characters.arya}}
in the template.
http://plnkr.co/edit/3PRgQSGdBEIDKuUSyDLY?p=preview
If you need to pass the name as an attribute to your child components, you have to put the child components inside the parent's template so you can call $ctrl.
http://plnkr.co/edit/1H7OlwbumkNuKKrbu4Vr?p=preview

how can I select a tab from outside controller

I'm using Tabs (ui.bootstrap.tabs) control\directive described here. The control creates it's own controller which sets active tab:
.controller('TabsetController', ['$scope', function TabsetCtrl($scope) {
var ctrl = this,
tabs = ctrl.tabs = $scope.tabs = [];
ctrl.select = function(selectedTab) {
angular.forEach(tabs, function(tab) {
if (tab.active && tab !== selectedTab) {
tab.active = false;
tab.onDeselect();
}
});
selectedTab.active = true;
selectedTab.onSelect();
};
Tabset child tab controls (child elements) can trigger parent's select function when clicked on them.
.directive('tab', ['$parse', function($parse) {
return {
require: '^tabset',
scope: {
onSelect: '&select',
I have my custom controller upwards the DOM which needs to trigger select function on TabsetController to set first tab active. I've read that I could use event broadcasting but I can't modify TabsetController to bind event listener so this doesn't seem to be a viable option. Any suggestions?
EDIT:
Please see Plunker for better understanding - here.
You can declare a scope attribute within the "parent" controller and it will be accessible in the child controller.
see: AngularJS - Access to child scope
Because TabsetController is set on a child DOM element while the MainController is set on a parent element, you can define and manipulate $scope.tabs in the MainController, and it will be seen and intepreted in TabsetController.

Can I change a directive's controller for different instances of the directive?

I have created a directive called modalDialog, which is basically that, a modal dialog. It uses transclude, so I can later do this in my code:
<div modal-dialog id="dialog" dialog-title="This is my Dialog">
...
here goes the content of the dialog
</div>
I want to use this directive in different places of my application, and for different purposes. The content of the dialogs will vary, naturally, so it would be very nice to have a way to pass the Controller to the directive, in the same way that I pass the dialog-title or any other parameter.
I thought about wrapping the modal-dialog in a div, with a controller set on it. Like this:
<div ng-controller="ThisInstanceController">
<div modal-dialog id="dialog" dialog-title="This is my Dialog">
...
here goes the content of the dialog
</div>
</div>
But I don't quite like it. Is there a more elegant way to do it?
Take a look at Angular-UI modals. They have a pretty elegant way of using modals. In short you can pass which controller you'd like to initialize when the modal opens.
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log('Modal dismissed at: ' + new Date());
});
};
The nice part as well is you can pass data with the resolve between controllers.

Resources