I are trying to bind a $scope.model.value to a popover.
With all the articles I have something working by storing a copy in the $scope then using a watch to update it if it changes who ever that is not a viable solution as I want to take the popover and use it multiple times with different arrays.
my html on the the main body is:
<button href="#" colorpopover
type="button"
class="btn btn-success btn-rainbow"
data-toggle="popover"
data-trigger="click"
title="Button Color"
id="static-color-popover-{{$id}}"
ng-model="model.value.buttonStatic.buttonColor">
Button Color
</button>
my controller has this code
app.directive('colorpopover', function ($compile, $templateCache, $q, $http) {
var getTemplate = function () {
var def = $q.defer();
var template = '';
template = $templateCache.get('/App_Plugins/IBD.ButtonStyles/Popovers/IBD.Color.Popover.html');
if (typeof template === "undefined") {
$http.get("/App_Plugins/IBD.ButtonStyles/Popovers/IBD.Color.Popover.html").then(function (data) {
$templateCache.put("templateId.html", data);
def.resolve(data);
});
} else {
def.resolve(template);
}
return def.promise;
}
return {
restrict: "A",
link: function (scope, element, attrs, model) {
getTemplate().then(function (popOverContent) {
// Make sure to remove any popover before hand (please confirm the method)
var compileContent = $compile(popOverContent.data)(scope);
var options = {
bindToController: true,
content: compileContent,
placement: "left",
html: true,
date: scope.date, };
$(element).popover(options);
});
}
};
});app.directive('colorpopover', function ($compile, $templateCache, $q, $http) {
var getTemplate = function () {
var def = $q.defer();
var template = '';
template = $templateCache.get('/App_Plugins/IBD.ButtonStyles/Popovers/IBD.Color.Popover.html');
if (typeof template === "undefined") {
$http.get("/App_Plugins/IBD.ButtonStyles/Popovers/IBD.Color.Popover.html").then(function (data) {
$templateCache.put("templateId.html", data);
def.resolve(data);
});
} else {
def.resolve(template);
}
return def.promise;
}
return {
restrict: "A",
link: function (scope, element, attrs, model) {
getTemplate().then(function (popOverContent) {
// Make sure to remove any popover before hand (please confirm the method)
var compileContent = $compile(popOverContent.data)(scope);
var options = {
bindToController: true,
content: compileContent,
placement: "left",
html: true,
date: scope.date, };
$(element).popover(options);
});
}
};
});
the template in basic terms
is
<div class="row">
<div ng-repeat="colorGroup in model.value" ng-class="!$last ? '' : 'last'">
<p>{{colorGroup.val1}}</p>
<p>{{colorGroup.val2}}</p>
<p>{{colorGroup.val3}}</p>
the model structure is
$scope.model.value.buttonStatic.buttonColor[val1,val2,val3]
$scope.model.value.buttonStatic.buttonHover[val1,val2,val3]
$scope.model.value.buttonStatic.buttonFocus[val1,val2,val3]
so eventually I want three buttons as a above with each of the tree values passed.
so at present the ng-repeat is repeating on the model.value of the child scope which is a direct copy of the parent.
the value in the template is going to change on the popover so it needs to go back to the parent.
With much trial and error I have solved the problem.
in the directive I needed to tie add these 2 line before the link.
require: 'ngModel', // ensures the model is passed in
scope: { model: '=ngModel' }, //ties the ng-model to the scope of the popover
then all I needed to do was set the ng-model in my button to model.value......
and in the popover template i just use model
My Main.Html which contains the tab directives.
<div class="modal-header">
<span class="modal-title">Add Report Template</span>
<div class="closeButton right" ng-click="closeModal()"></div>
</div>
<div class="modal-body">
<tab-set>
<tab heading="1st Tab">
This is the content for 1st Tab
</tab>
<tab heading="2nd Tab">
This is the content for 2nd tab
</tab>
<tab heading="3rd Tab">
This is the content for 3rd tab.
</tab>
</tab-set>
</div>
<div class="modal-footer">
<div>
<button type="text" class="grayButton right" ng-click="goToNextTab()">Next</button>
<button type="text" class="grayButton left" ng-click="goToPreviousTab()">Back</button>
</div>
</div>
My Main.controller where i need the define the function for Next and Back Button
(function () {
'use strict';
angular
.module('myApp')
.controller('Controller', ['$scope', function($scope,) {
var vm = this;
/////////////// Function to Change tab on click of the Back/Next Button ///////////////
$scope.goToNextTab = function() {
};
$scope.goToPreviousTab = function() {
};
}]);
})();
My TabSet directive that displays the 3 tabs.
angular
.module('myApp')
.directive('TabSet', function() {
return {
restrict: 'E',
transclude: true,
scope: { },
templateUrl: 'tabset.html',
bindToController: true,
controllerAs: 'tabs',
controller: function($scope) {
var self = this;
self.tabs = [];
self.addTab = function addTab(tab) {
self.tabs.push(tab);
if(self.tabs.length === 1) {
tab.active = true;
}
};
self.select = function(selectedTab) {
angular.forEach(self.tabs, function(tab) {
if(tab.active && tab !== selectedTab) {
tab.active = false;
}
});
selectedTab.active = true;
};
}
};
});
Tabset Html for the corresponding tabset directive.
<div role="tabpanel" class="tabsets">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" ng-repeat="tab in tabs.tabs" ng-class="{'active': tab.active}">
{{tab.heading}}
</li>
</ul>
<div ng-transclude></div>
</div>
This is the Tab directive for creating the individual tabs.
angular
.module('myApp')
.directive('Tab', function() {
return {
restrict: 'E',
transclude: true,
template: `<div role="tabpanel" ng-show="active"><div ng-transclude></div></div>`,
require: '^TabSet',
scope: {
heading: '#'
},
link: function(scope, elem, attr, tabs) {
scope.active = false;
tabs.addTab(scope);
}
}
});
I am not too sure what I am missing, but for the given structure I want to switch tabs based on click of the Next as well as Back Button defined in main.html.
I see your code is wrong on link function of Tab directive.
link: function(scope, elem, attr, reporttabs) {
scope.active = false;
tabs.addTab(scope);
}
You need to change tabs.addTab to reporttabs.addTab
And here is the solution for the feature you want to implement. You need to add a selectedTabIndex property into scope of Tabset. So you can use scope.$watch function and when the selectedTabIndex has changed you can call scope.select(selectedTab). Here code example:
angular
.module('myApp')
.controller('Controller', ['$scope', function($scope,) {
var vm = this; vm.selectedTabIndex = 0;
$scope.goToNextTab = function() {
vm.selectedTabIndex += 1;
};
$scope.goToPreviousTab = function() {
vm.selectedTabIndex -= 1;
};
}]);
angular
.module('myApp')
.directive('TabSet', function() {
return {
restrict: 'E',
transclude: true,
scope: { 'selectedTabIdex': '=' },
templateUrl: 'tabset.html',
bindToController: true,
controllerAs: 'tabs',
controller: function($scope) {
var self = this;
self.tabs = [];
self.addTab = function addTab(tab) {
self.tabs.push(tab);
if(self.tabs.length === 1) {
tab.active = true;
}
};
self.select = function(selectedTab) {
angular.forEach(self.tabs, function(tab) {
if(tab.active && tab !== selectedTab) {
tab.active = false;
}
});
selectedTab.active = true;
};
$scope.$wacth('selectedTabIndex', function(newValue, oldValue) {
var index = newValue;
if(index >= self.tabs.length) {
return $scope.selectedTabIndex = 0;
}
if(index < 0) {
return $scope.selectedTabIndex = self.tabs.length - 1;
}
self.select(self.tabs[index]);
});
}
};
});
I a trying to access controller scope in my directive but can't access. I created a directive 'dynamicElement' to create new HTML element and its working fine, but in my directive i am not able to access my controller scope.
My Code: Controller
.controller('DashCtrl', function($scope, SurveyQuest, $state, $stateParams, $sce) {
var QuestData = SurveyQuest.all();
if($state.params.qid == ''){
var questionOrder = 1;
}else{
var questionOrder = $state.params.qid;
}
//console.log(QuestData.data[paramQid]);
//console.log(QuestData);
//console.log(QuestData.data.length);
var paramQid;
angular.forEach(QuestData.data, function(value, key) {
if(value.question_order == questionOrder){
paramQid = key;
}
//console.log(value.question_order+' '+key);
});
console.log(paramQid);
console.log(QuestData.data);
$scope.question = $sce.trustAsHtml(QuestData.data[paramQid].question_text);
$scope.description = $sce.trustAsHtml(QuestData.data[paramQid].question_desc);
switch(QuestData.data[paramQid].question_type){
case'radio':
var radioLength = QuestData.data[paramQid].answers.length;
var finalAnswers = '';
for(var i = 0; i < radioLength; i++){
finalAnswers+= '<label><input type="radio" ng-click="clickMe($event)" data-id="'+QuestData.data[paramQid].answers[i].option_next+'" name="'+QuestData.data[paramQid].question_id+'" value="'+QuestData.data[paramQid].answers[i].option_value+'" /> '+QuestData.data[paramQid].answers[i].option_text+'</label>';
}
$scope.htmlString = finalAnswers;
break;
.............
$scope.next = function(qid){
console.log(qid);
$state.go('tab.dash',{'qid':qid});
}
View Code:
<dynamic-element message='htmlString' ng-bind-html="ans"></dynamic-element>
<div class="buttons" style="text-align:center; margin-top:10%;">
<button class="button button-positive">
Prev
</button>
<button class="button button-assertive" >
Stop
</button>
<button class="button button-balanced" ng-click="next({{qid}})">
Next
</button>
</div>
Directive Code:
.directive('dynamicElement', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
message: "="
},
replace: true,
link: function(scope, element, attrs) {
var template = $compile(scope.message)(scope);
element.replaceWith(template);
},
controller: ['$scope', function($scope) {
$scope.clickMe = function(item){
$scope.qid = item.currentTarget.getAttribute("data-id"); //NOT WORKING
console.log(item.currentTarget.getAttribute("data-id"));
};
}]
}
}])
Kindly suggest me..Thanks
The code below wraps a KendoWindow in a directive. The objective is twofold: (1) to open/close KendoWindow via $broadcast and avoid having window open/close methods in the controller (as these methods modify the DOM and not the model), and (2) use transclusion to define in the component child elements that will be shown in the KendoWindow and handled in the controller.
The problem is that the elements don't show up in the KendoWindow (see plunk) and the drow down list doesn't work. What's wrong with this code?
HTML:
<button ng-click="open()">Open window</button>
<button ng-click="close()">Close window</button>
<div my-window title="'This is the title'">
<p>Some HTML content</p>
This is a link
<select kendo-drop-down-list="ddl" style="width: 200px" k-options="ddlOptions">
<option>xxx</option>
<option>yyy</option>
<option>zzz</option>
</select>
</div>
Javascript:
var app = angular.module("app", [ "kendo.directives" ]);
function MyCtrl($scope) {
$scope.open = function () {
$scope.$broadcast('open');
};
$scope.close = function () {
$scope.$broadcast('close');
};
$scope.ddlOptions = {
select: function() {
alert('selected');
}
};
}
app.directive('myWindow', function() {
var directive = {};
directive.restrict = 'AE';
directive.transclude = true;
directive.scope = { title: '=' };
directive.template = '<div kendo-window="win" k-width="500" k-visible="false" ng-transclude></div>';
directive.link = function(scope, element, attrs) {
var init = function() {
scope.win.title(scope.title);
};
scope.$on("open", function(){
scope.win.center();
scope.win.open();
});
scope.$on("close", function(){
scope.win.close();
});
scope.$on("kendoWidgetCreated", function(event, widget){
if (widget === scope.win ) {
init();
}
});
};
return directive;
});
So I'm trying to implement a custom confirm box using Angular. Ideally, I would simply like to add an attribute to enable the functionality. Example:
<button type="button" ng-click="delete(foo)">Delete</button> -> <button type="button" ng-click="delete(foo)" ng-confirm="Are you sure you want to delete this foo?">Delete</button>
(foo is inside an ng-repeat... foo in fooList..)
So all of the problems I am having revolve around tying the click event that would normally happen to a different button. I have a seperate directive "confirmBox" that will create my modal (not using bootstrap) and handle all of the showing/hiding/etc.
What I am currently using requires me to alter my ng-click functionality, which I really want to get away from:
Current Implementation:
<button ... ng-click="confirm('Are you sure you want to delete this foo?, 'delete', foo)">Delete</button>
var confirmModule = angular.module('confirm', []);
confirmModule.run(function($rootScope) {
$rootScope.confirm = function(text, func, obj) {
$rootScope.$broadcast('confirm', func, obj, text);
};
});
confirmModule.directive('confirmBox', function($parse) {
return {
restrict: 'A',
template: myModalTemplate,
link: function(scope, element, attrs){
element.hide();
var noBtn = element.find("[name='no']");
noBtn.bind("click", function() {
element.hide();
});
scope.$on("confirm", function(event, func, obj, text) {
var yesBtn = element.find("[name='yes']");
element.show();
yesBtn.unbind("click").bind("click", function() {
scope[func](obj);
});
});
}
}
});
Anyone have any ideas? I started by adding the directive for the button and then unbinding the click event so ng-click doesn't fire. Then I am left with the string 'delete(foo)' from the ng-click attribute that I can execute with $parse(attrs.ngClick)(scope), but I don't know how to tie that to the separate directives button click.
Edit: Here is a fiddle with my current attempt at implementation. The problem is the variable being passed in to the function is always undefined.
http://jsfiddle.net/UCtbj/2/
Edit2: Updated implementation, however I don't particularly like how it links the two directives together by targetting the other directives elements.
http://jsfiddle.net/UCtbj/3/
It seems to me that you're trying to do things the jQuery way from within the directive. However, what you want is as simple as pulling in the UI-Bootstrap directive for confirming actions. http://plnkr.co/edit/JhfAF1?p=preview
First simple service for modal windows:
app.service('ConfirmService', function($modal) {
var service = {};
service.open = function (text, onOk) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalConfirmCtrl',
resolve: {
text: function () {
return text;
}
}
});
modalInstance.result.then(function (selectedItem) {
onOk();
}, function () {
});
};
return service;
})
app.controller('ModalConfirmCtrl', function ($scope, $modalInstance, text) {
$scope.text = text;
$scope.ok = function () {
$modalInstance.close(true);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
Then simple directive that uses it:
app.directive('confirm', function(ConfirmService) {
return {
restrict: 'A',
scope: {
eventHandler: '&ngClick'
},
link: function(scope, element, attrs){
element.unbind("click");
element.bind("click", function(e) {
ConfirmService.open(attrs.confirm, scope.eventHandler);
});
}
}
});
And here u go:
<button ng-click="test(12)" confirm='Are you sure?'>Button</button>
http://plnkr.co/edit/LOZOnsVyx3JU5XoKYn74?p=preview
To allow a button to be marked up like
<button type="button" ng-click="deleteItem(drink)" ng-confirm="Are you sure you want to delete '{{drink.name}}'">Delete</button>
You can write a directive that
Intercepts the click event before ngClick's click handler can run
Opens a dialog (using $modal and not the removed $dialog)
On close of the dialog (which is treated as a success) run the function specified by the ngClick attribute on the element.
Basing the code on the previous answer, you can do this as follows:
app.directive('ngConfirm', function($modal, $parse) {
return {
// So the link function is run before ngClick's, which has priority 0
priority: -1,
link: function(scope, element, attrs) {
element.on('click', function(e) {
// Don't run ngClick's handler
e.stopImmediatePropagation();
$modal.open({
templateUrl: 'ng-confirm-template',
controller: 'ngConfirmController',
resolve: {
message: function() {
return attrs.ngConfirm;
}
}
}).result.then(function() {
// Pass original click as '$event', just like ngClick
$parse(attrs.ngClick)(scope, {$event: e});
});
});
}
};
});
which needs a simple controller:
app.controller('ngConfirmController', function($scope, $modalInstance, message) {
$scope.message = message;
$scope.yes = function() {
$modalInstance.close();
};
$scope.no = function() {
$modalInstance.dismiss();
};
});
and template for the dialog:
<script type="text/ng-template" id="ng-confirm-template">
<div class="modal-body">
<p>{{message}}</p>
</div>
<div class="modal-footer">
<button class="btn btn-link pull-left" ng-click="no()">No</button>
<button class="btn btn-primary pull-right" ng-click="yes()">Yes</button>
</div>
</script>
You can see this running at http://plnkr.co/edit/Gm9lFsGb099w6kCMQoVY?p=preview
Edit: changed plunker link to example without scrollbar appearing/disappearing on display of the dialog
Here is a nice directive for that.That is ngBootbox. Check it out.
<button class="btn btn-lg btn-primary"
ng-bootbox-title="A cool title!"
ng-bootbox-custom-dialog="Some custom text"
ng-bootbox-buttons="customDialogButtons"
ng-bootbox-class-name="some-class">
Custom dialog
</button>
<script>
$scope.customDialogButtons = {
warning: {
label: "Warning!",
className: "btn-warning",
callback: function() { $scope.addAction('Warning', false); }
},
success: {
label: "Success!",
className: "btn-success",
callback: function() { $scope.addAction('Success!', true) }
},
danger: {
label: "Danger!",
className: "btn-danger",
callback: function() { $scope.addAction('Danger!', false) }
},
main: {
label: "Click ME!",
className: "btn-primary",
callback: function() { $scope.addAction('Main...!', true) }
}
};
</script>
Demo
ngBootbox
I created a repo for this functionality. It wraps the ui-bootstrap modal to produce a confirmation box. It is customizable and easily integrated into any application.
Here is the link to the GitHub: https://github.com/Schlogen/angular-confirm
Example Usages:
As a directive:
<button type="button" ng-click="delete()" confirm-if="checked" confirm="Are you sure, {{name}}?">Delete</button>
As a service:
$confirm({text: 'Are you sure you want to delete?'})
.then(function() {
$scope.deletedConfirm = 'Deleted';
});
Ok, here is the one I ended up going with
1) Create a service for the dialog
app.service('dialogModal', [
'$modal', function($modal) {
return function(message, title, okButton, cancelButton) {
okButton = okButton === false ? false : (okButton || 'Yes');
cancelButton = cancelButton === false ? false : (cancelButton || 'No');
var modalInstance = $modal.open({
templateUrl: '/templates/deletePrompt.html',
controller: ModalInstanceCtrl,
resolve: {
settings: function() {
return {
modalTitle: title,
modalBody: message,
okButton: okButton,
cancelButton: cancelButton
};
}
}
});
// return the modal instance
return modalInstance;
}
}
]);
2) Create a controller and pass the model instance in it
var ModalInstanceCtrl = function ($scope, $modalInstance, settings) {
angular.extend($scope, settings);
$scope.ok = function () {
$modalInstance.close(true);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
3) included the link into the header to take on default styling
<link data-require="bootstrap-css#3.x" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
4) overwrote the styling in my own css
5) Here is my delete prompt template
<div id="overlayClearMainDiv" class="dialog-modal">
<div id="overlayClearText">
<span>{{modalBody}}</span>
</div>
<div id="overlayClearButton">
<button id="overlayClearYesButton" class="confirmButton" type="button" ng-click="ok()" ng-show="okButton">{{okButton}}</button>
<button class="confirmButton-white" ng-click="cancel()" ng-show="cancelButton">{{cancelButton}}</button>
</div>
</div>
Here's a quick one for you - http://plnkr.co/edit/YklthDZcknmvMjU5A6pe?p=preview
So basically if you are interested in showing a modal dialog once a user clicks on let's say, a button there's no need to make it difficult.
All you need is a simple directive that encapsulate $modal service found in ui-bootstrap.
In my simple example I just pass in a string representing a message and then defining a on-confirm attribute that my directive invokes once the user confirms. Invoking the function itself leverages the awesomeness of $parse to resolve the expression and once resolved, invoke it with the scope.
Nice and clear and here's how it looks like.
View
<body ng-controller="AppController">
<input type="button" value="Delete"
confirm="'Are you sure you want to delete me?'" on-confirm="delete()" />
<script type="text/ng-template" id="modal.html">
<div class="modal-header">
<h3 class="modal-title">Confirm</h3>
</div>
<div class="modal-body">
<p>The world won't be a better place if you delete me.</p>
</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>
</body>
Controller / Directive
angular
.module('App', ['ui.bootstrap'])
.controller('AppController', ['$scope', function($scope){
$scope.delete = function(){
alert('Woho, Im deleted!');
};
}])
.directive('confirm', ['$modal', '$parse', function($modal, $parse){
return {
link: function(scope, el, attr){
el.bind('click', function(){
var instance = $modal.open({
templateUrl: 'modal.html',
controller: ['$scope', '$modalInstance', modalController]
});
instance.result.then(function(){
// close - action!
$parse(attr.onConfirm)(scope);
},function(){
// dimisss - do nothing
});
});
}
};
function modalController(modalScope, $modalInstance){
modalScope.ok = function(){
modalInstance.close();
};
modalScope.cancel = function(){
modalInstance.dismiss();
};
}
}]);