I've been trying to create a directive which I can arbitrarily add to an existing form (as attribute), which makes the form become a popover upon clicking on a nearby trigger link. I've got the directive to work once, but once I click the link again, the underlying data does not change and the buttons (eg. 'close') stop working.
A plunker can be found here: http://plnkr.co/edit/2Zyg1bLearELpofeoj2T?p=preview
Steps to reproduce: 1. Click on link, 2. Change text (note that link text changes as well), 3. Click close (ok doesn't do the right thing at current), 4. Click on link again, 5. Try to change text/click close, but nothing works...
I've read that a problem is that popovers in bootstrap are detached/attached to the DOM, but I don't know how I could resolve this issue anyway. I also would like to avoid third party libraries (such as angular-ui), as I'd like to avoid the overhead.
Any help is greatly appreciated.
Update
Thanks to Vasaka's hint, I was able to progress a little further. The problem slightly changed in that the nested directive now does not seem to benefit from the $compile, i.e. I don't believe it is attached to the scope.
To reproduce the behaviour, click on the date (plunker link below), click on the date in the popover (date should increment) and close the popover. Repeating the steps again, you will notice that incrementing the date doesn't work any more. I tried to add $compile(element.contents())(scope) in an attempt to also compile the nested directive simple-date-picker, but this didn't resolve the issue.
Here's the updated plunker: http://plnkr.co/edit/2Zyg1bLearELpofeoj2T?p=preview
And the updated code:
<!DOCTYPE html>
<html>
<head>
<link data-require="bootstrap-css@*" data-semver="3.0.3" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" />
<script data-require="[email protected]" data-semver="1.9.1" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script data-require="[email protected]" data-semver="2.3.2" src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script data-require="[email protected]" data-semver="1.2.5" src="http://code.angularjs.org/1.2.5/angular.js"></script>
<style>
body {margin-top:40px; margin-left:40px;}
</style>
<script>
var module = angular.module('module', []);
module.directive('simpleDatePicker', function($compile) {
return {
restrict: 'E',
scope: {
date: '='
},
replace: true,
template: '<div ng-click="date.setDate(date.getDate()+5)"> {{ date }} </div>',
}
});
module.directive('myForm', function() {
return {
restrict: 'E',
scope: {
popover: '=?',
value: '='
},
transclude: true,
replace: true,
template:
'<div>' +
'<a href="" ng-transclude></a>' +
'<form ng-submit="submit($event)" ng-hide="popover && !formVisible" ng-attr-popover="{{ popover }}" class="form-inline">' +
'<simple-date-picker date="value"></simple-date-picker>' +
'<div ng-hide="!popover">' +
'<button type="submit" class="btn btn-primary">OK</button>' +
'<button type="button" class="btn" ng-click="formVisible=false">close</button>' +
'</div>' +
'<div class="editable-error help-block" ng-show="error">{{ error }}</div>' +
'</form>' +
'</div>',
controller: function($scope, $element, $attrs) {
$scope.formVisible = false;
$scope.submit = function(evt) {
$scope.formVisible = false;
}
}
}});
module.directive('popover', function($compile) {
return {
restrict: 'A',
scope: false,
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
},
post: function postLink(scope, iElement, iAttrs, controller) {
var attrs = iAttrs;
var element = iElement;
// We assume that the trigger (i.e. the element the popover will be
// positioned at is the previous child.
var trigger = element.prev();
var popup = element;
// Connect scope to popover.
trigger.on('shown', function() {
var tip = trigger.data('popover').tip();
$compile(tip)(scope);
scope.$digest();
});
trigger.popover({
html: true,
content: function() {
scope.$apply(function() {
scope.formVisible = true;
});
return popup;
},
container: 'body'
});
scope.$watch('formVisible', function(formVisible) {
if (!formVisible) {
trigger.popover('hide');
}
});
if (trigger.data('popover')) {
trigger.data('popover').tip().css('width', '500px');
}
}
}
}
};
});
function MyCtrl($scope) {
$scope.value = new Date(0);
}
angular.element(document).ready(function() {
angular.bootstrap(document, ['module']);
});
</script>
</head>
<body ng-controller="MyCtrl">
<my-form popover="true" value="value">
{{ value }}
</my-form>
</body>
</html>