Angular Directive function call on ng-change - angularjs

I have an angular-bootstrap modal popup box that contains a custom directive in the template:
Modal.html
<div class="modal-header">
<h3 class="modal-title">Modal Header</h3>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<my-directive ng-model="test" ng-change="doSomething()" />
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="upload()">Upload</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
ModalCtrl.js
app.controller('ModalCtrl', function ModalCtrl( $scope, $modalInstance ) {
$scope.test = 'empty';
$scope.upload = function() {
$scope.test = 'change!';
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
});
I open the modal popup from my main controller like this:
MainCtrl.js
var app = angular.module( 'myApp', [ 'ui.bootstrap' ] );
app.controller('MainCtrl', function MainCtrl( $scope, $modal ) {
$scope.openModal = function() {
var modalInstance = $modal.open({
templateUrl: '/assets/modals/Modal.html',
controller: 'ModalCtrl',
size: 'md'
});
};
});
As you can see from the above code, the modal template contains my custom directive <my-directive> which takes $scope.test - defined in the ModalCtrl - as it's model and should call $scope.doSomething() when that model changes.
The custom directive looks like this:
MyDirective.js
angular.module( 'myApp' ).directive( 'myDirective', function() {
return {
controller: function( $scope ) {
$scope.doSomething = function() {
console.log( 'doSomething() called! $scope.test now = ' + $scope.test );
};
},
link: function( $scope, el, att ) {
console.log( '$scope.test = ' + $scope.test );
},
template: '<div class="thumbnail"></div>'
};
} );
When the modal popup opens the console prints out $scope.test = empty which is exactly what I expect to see. But when $scope.test is changed by calling the $scope.upload() function in ModalCtrl nothing happens! What I think should happen is $scope.doSomething() is called which then should print out in the console doSomething() called! $scope.test now = change!.
Any help would be much appreciated, this is driving me mad!

I figured it out. Instead of using ng-model and ng-change I added:
scope: {
test: '#'
}
to my directive and added this into my link function:
$scope.$watch( 'test', function() {
console.log( 'test changed' );
} );
Then I add test as a parameter in my directives tag like so:
<my-directive test="test" />
and finally whenever I change $scope.test I call $scope.$apply() and voila!

Related

AngularJS call AngularStrap Modal from service

I am trying to create a service to display Angular-Strap modals since I have many different parts of code that will need to trigger a modal and I don't want to run into a situation where I would have a circular reference.
This is code that works where you have access to $scope. For instance, in the applications controller.
function MyModalController($scope) {
$scope.title = 'Draw Object Properties';
$scope.content = 'Hello Modal<br />This is place holder test';
};
MyModalController.$inject = ['$scope'];
// Pre-fetch an external template populated with a custom scope
var myOtherModal = $modal({ controller: MyModalController, templateUrl: 'webmapapi/modal/toolproperties.html', show: false });
// Show when some event occurs (use $promise property to ensure the template has been loaded)
$scope.showModal = function () {
myOtherModal.$promise.then(myOtherModal.show);
};
Like I said I need to call this from a service though.
(function (angular, undefined) {
'use strict';
angular.module('ModalService', ['service', 'webValues', 'msObjects', 'mgcrea.ngStrap',])
.config(function ($modalProvider) {
angular.extend($modalProvider.defaults, {
html: true
});
})
.factory("ModalService", function (MapApiService, webValues, VectorObjs,$modal) {
var modalSVC = {
};
modalSVC.showModal = function (modalType) {
var scope = angular.element(document.getElementById('mainContainer')).scope();
function MyModalController(scope) {
scope.title = 'Draw Object Properties';
scope.content = 'Hello Modal<br />This is place holder test';
};
MyModalController.$inject = ['scope'];
// Pre-fetch an external template populated with a custom scope
var myOtherModal = $modal({ controller: MyModalController, templateUrl: 'myURL.html', show: true });
// Show when some event occurs (use $promise property to ensure the template has been loaded)
myOtherModal.show;
};
return modalSVC;
})
}(angular));
The above does not like the scope I'm getting.
Okay, It's amazing how easy something can be once you know what you are doing!!
Essentially you will want to set up a service...
(function (angular, undefined) {
'use strict';
angular.module('ModalService', ['mgcrea.ngStrap'])
.controller('ModalServiceController', modalServiceController)
.factory("ModalService", function ($animate, $document, $compile, $controller, $http, $rootScope, $q, $templateRequest, $timeout, $modal) {
function ModalService() {
var self = this;
self.showModal = function (title,templateUrl) {
var modal = $modal({
title: title,
templateUrl: templateUrl,
show: true,
backdrop: 'static',
controller: 'ModalServiceController'
});
modal.show;
};
}
return new ModalService();
})
modalServiceController.$inject = ['$scope', '$modal'];
function modalServiceController($scope,$modal) {
//title and content need to be populated so I just left the default values
$scope.title = 'Draw Object Properties';
$scope.content = 'Hello Modal<br />This is place holder test';
};
}(angular));
Now that you have your controller set up and injecting $modal, all you have to do from anywhere you have your service reference injected is...
ModalService.showModal("Your Title",
"Your URL");
I have a template(must be formatted as ) set up as Template.html and the contents are...
<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" ng-show="title">
<button type="button" class="close" ng-click="$hide()">×</button>
<h4 class="modal-title" ng-bind-html="title"></h4>
</div>
<div class="modal-body" ng-show="content">
<h4>Text in a modal</h4>
<p ng-bind-html="content"></p>
<pre>2 + 3 = {{ 2 + 3 }}</pre>
<h4>Popover in a modal</h4>
<p>This <a href="#" role="button" class="btn btn-default popover-test" data-title="A Title" data-content="And here's some amazing content. It's very engaging. right?" bs-popover>button</a> should trigger a popover on click.</p>
<h4>Tooltips in a modal</h4>
<p><a href="#" class="tooltip-test" data-title="Tooltip" bs-tooltip>This link</a> and <a href="#" class="tooltip-test" data-title="Tooltip" bs-tooltip>that link</a> should have tooltips on hover.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$hide()">Close</button>
<button type="button" class="btn btn-primary" ng-click="$hide()">Save changes</button>
</div>
</div>
</div>
I hope this helps you!!

Angular modal- the modal is displayed from the start and I can't hide it

I am new to angular js
I have to open a modal dialog which display some selected value.
Open Modal
<div modal="showModal" close="cancel()">
<div class="modal-header">
<h4>Modal Dialog</h4>
</div>
<div class="modal-body">
<p>E{{inputValue}}</p>
</div>
<div class="modal-footer">
<button class="btn btn-success" ng-click="ok()">Okay</button>
<button class="btn" ng-click="cancel()">Cancel</button>
</div>
</div>
The controller for the module which contain the modal is:
var app = angular.module('myApp', ['ui.bootstrap.modal']);
app.controller('ctrlTags', function($scope){
$scope.inputValue=$('input:checked').val()
$scope.open = function() {
$scope.showModal = true;
return $scope.inputValue;
};
$scope.ok = function() {
$scope.showModal = false;
};
$scope.cancel = function() {
$scope.showModal = false;
};
});
For some reason the modal is displayed as is it is a regular part of the page (doesn't function as a modal)
Toggling a boolean is not how ui-boostrap modals are opened. See documentation. Basically you have to call $uibModal.open with a template:
$scope.open = function() {
var modalInstance = $uibModal.open({
templateUrl: 'myModal.html',
controller: 'ModalInstanceCtrl'
});
}
Have a look at this plunker where I'm passing a value to the modal, through the resolve property of $uibModal.open.

angularjs modal initialization using factory

Trying to make a modal window opening in controller, using app.factory.
Getting strange error and don't understand what the problem.
So, this is the error i got in js console:
Error: [$injector:unpr] http://errors.angularjs.org/1.3.15/$injector/unpr?p0=modalServiceProvider%20%3C-%20modalService%20%3C-%20MapController
Here is my files and structure:
Main controller:
app.controller('MainController', ['$scope', 'modalService', function($scope, modalService){
///Modal: Add item
//////////////////
console.log('dfdfdf');
$scope.AddItem = modalService.openAddItemDialog($scope);
}]);
open it on simple HTML:
<div ng-controller="MainController">
<button type="button" class="btn btn-block" ng-click="AddItem()"> </button>
</div>
Factory:
app.factory('modalService', ['$modal', function($modal) {
function openAddItemDialog($scope) {
console.log('dfdfdf');
$scope.animationsEnabled = true;
$scope.valueToPass = "I must be passed";
var modalInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'AddItemDialog.html',
controller: 'AddItemController',
resolve: {
aValue: function () {
return $scope.valueToPass;
}
}
});
modalInstance.result.then(function (paramFromDialog) {
$scope.paramFromDialog = paramFromDialog;
});
}
return {
openAddItemDialog: openAddItemDialog
};
}]);
Modal Controller:
app.controller('AddItemController',function($scope, $modalInstance, aValue) {
$scope.valuePassed = aValue;
$scope.close = function () {
$modalInstance.close("Someone Closed Me");
};
});
HTML template:
<div class="modal-header">
<h2>The title</h2>
</div>
<div class="modal-body">
The body of the dialog with the value to pass '{{valuePassed}}'
</div>
<div class="modal-footer">
<button class="btn" ng-click="close()">Close</button>
</div>
i even don't see the first console.log('dfdfdf'); func result. so it broke main controller's work in some way.. but blind, can't se, whats the problem? for me, looks like all should work.
** app is defined in separate file like var app = angular.module('MainPage', ['ui.bootstrap']);
Can you double check that you have included the service file in your app page?
You can find more info about this error here

Compile a dynamic directive inside a template

I have a directive like this:
foldeskApp.directive('contributionFooter', function() {
return {
restrict: 'C',
template: '<button type="button" class="btn" ng-class="{\'btn-success\': canCreate()}">Add</button>'
};
});
And a controller like this:
foldeskApp.controller('MainCtrl',
['Auth', '$scope', function(Auth, $scope) {
$scope.footerType = 'contribution';
}]);
Can I call the directive like this?
<div class="modal-footer {{footerType}}-footer"></div>
You need to compile the DOM using the $compile service.
Here's an example of how to achieve that, although I'm not a fan of using $timeout here:
http://codepen.io/jlowcs/pen/jEKKjZ
HTML:
<div ng-controller="MainCtrl">
<div class="modal-footer {{footerType}}-footer"></div>
</div>
JS:
angular.module('exampleApp', [])
.directive('contributionFooter', function() {
return {
restrict: 'C',
template: '<button type="button" class="btn" ng-class="{\'btn-success\': canCreate()}">Add</button>'
};
})
.controller('MainCtrl', function($scope, $element, $timeout, $compile) {
$scope.footerType = 'contribution';
//timeout to do it when {{footerType}} has been replaced
//but it would probably be best to do this in a link function in a directive
$timeout(function () {
$compile($element.children())($scope);
});
});
angular.bootstrap(document, ['exampleApp']);

Angular bootstrap ui modal scope binding with parent

I am having an Angular issue getting a modal scope to unbind from the parent scope. I want the scope object I pass into the modal to be separate from the corresponding scope object.
No matter how I structure the modal object the parent always mirrors it. The only solution I have found is to change the object property names, but that would be cumbersome to do for every modal in my project.
For example, I can have a $scope variable in the parent $scope.parentData.firstName and a modal variable $scope.modalData.a.b.c.firstName, and the parent will mirror the modal value.
I guess there is some parent child $scope issues here that I am not getting.
Here is a plunk illustrating the issue:
http://plnkr.co/edit/5naWXfkv7kmzFp7U2KPv?p=preview
HTML:
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3>I'm a modal!</h3>
</div>
<div class="modal-body">
<input ng-model="modalData.a" />
<input ng-model="modalData.b" />
<input ng-model="modalData.c" />
Selected: <b>{{ sourceData }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn btn-default" ng-click="open()">Open me!</button>
{{sourceData}}
<div ng-show="sourceData">Selection from a modal: {{ test }}</div>
</div>
</body>
</html>
JS:
angular.module('plunker', ['ui.bootstrap']);
var ModalDemoCtrl = function ($scope, $modal, $log) {
$scope.sourceData = {a:'abc',b:'bcd',c:'cde'};
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
data: function () {
return $scope.sourceData;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.scopeData = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
};
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope, $modalInstance, data) {
$scope.modalData = {};
$scope.modalData = data;
$scope.ok = function () {
$modalInstance.close($scope.modalData);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
You are passing a reference to your current object, what you want to do is use angular.copy() to pass a deep copy of the object to the modal plnkr:
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
data: function () {
return angular.copy($scope.sourceData); // deep copy
}
}
});

Resources