unable access controller scope from custom directive - angularjs

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

Related

Angularjs Confirmation Modal as Directive with action

I want to create angularjs directive mydialog wihc triggers the modal.Once the model is open I will have title and content,okcancel and confirm .Once the user click the confirm the corresponding action i.e. save should trigger .Here the save action is in MainCtrl .How to trigger that.
HTML Directive:
<my-dialog newmodal="alertModel" ></my-dialog>
ConfirmationDailog.html Code :
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-click="$hide()">×</button>
<h4 class="modal-title">{{alertModel.Title}}</h4>
</div>
<div class="modal-body">
{{alertModel.Message}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
<button type="button" class="btn btn-danger" ng-click="executeDialogAction(alertModel.action)">Confirm</button>
</div>
</div>
Below is the JS part :
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', ['$scope', '$uibModal',
function ($scope,$uibModal) {
$scope.name = 'World';
var alertModel = {};
alertModel.Title = "My Title";
alertModel.Message = "The Conent";
alertModel.action= "save";
$scope.alertModel = alertModel;
$scope.save= function () {
alert('from outside');
}
}]);
my Dialog Directive that triggers the model
app.directive('myDialog', [
function () {
return {
scope: {
mymodal: '=newmodal',
},
template: "<button class='btn btn-danger' ng-lick='open(mymodal)'>Open Modal</button>",
controller: ModalController
};
}]);
function ModalController($uibModal, $log, $scope) {
$scope.animationsEnabled = true;
$scope.open = function (alertModel) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'ConfirmationDailog.html',
controller: ModalInstanceCtrl,
scope:$scope,
resolve: {
test: function () {
return alertModel;
}
},
size: 'lg'
});
modalInstance.result.then(function (selectedItem) {
console.log("Confirmed: " + selectedItem);
$scope.selectedItem = selectedItem;
}, function () {
$log.info('modal dismissed at: ' + new Date());
});
};
}
function ModalInstanceCtrl($scope, $uibModalInstance, test) {
console.log('in');
$scope.alertModel = test;
$scope.cancel = function () {
$scope.$dismiss();
}
$scope.executeDialogAction = function (action) {
if (typeof $scope[action] === "function") {
$scope[action]();
}
};
}

Created a custom directive for tabs. On click of Next Button need to go to the next tab, and on click of back button need to come to previous tab

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]);
});
}
};
});

Angular Can't change ng-model form other directive

I need to change ng-model (currentPage) in pdfViewerToolbar directive by clicking on canvas in pdfViewer directive. The self.next function in controller is called when i clicking on canvas, but ng-model="currentPage" is not changed in pdfViewerToolbar directive.
app.angular.module("pdf").directive("pdfViewerToolbar", ["pdfDelegate", function(e) {
return {
restrict: "E",
template: '<div class="pdf_navigation" ng-show="navBar">\
<div class="pdf_buttons">\
<div ng-click="prev()" class="goPrevious" title="previous page"></div>\
<div ng-click="next()" class="goNext" id="goNext" title="next page"></div>\
<div ng-click="zoomOut()" class="zoomIn"></div>\
<div ng-click="zoomIn()" class="zoomOut"></div>\
</div>\
<div class="pdf_page">\
<span>Page</span>\
<input type="text" min=1 ng-model="currentPage" maxlength="4" ng-change="goToPage()" >\
<span>of {{pageCount}}</span>\
</div>\
</div>',
scope: {
pageCount: "=",
navBar: "=",
},
// controller: "PdfCtrl",
link: function(t, n, a) {
var o = a.delegateHandle;
t.currentPage = 1, t.prev = function() {
e.$getByHandle(o).prev(), r()
}, t.next = function() {
e.$getByHandle(o).next(), r()
}, t.zoomIn = function() {
e.$getByHandle(o).zoomIn()
}, t.zoomOut = function() {
e.$getByHandle(o).zoomOut()
}, t.rotate = function() {
e.$getByHandle(o).rotate()
}, t.goToPage = function() {
e.$getByHandle(o).goToPage(t.currentPage)
};
var r = function() {
t.currentPage = e.$getByHandle(o).getCurrentPage()
}
}
}
}])
app.angular.module("pdf").directive("pdfViewer", ["pdfDelegate", function(r) {
return {
restrict: "E",
template: '<div show-control class="pdf_doc"><pdf-viewer-toolbar ng-if="showToolbar" delegate-handle="{{id}}" page-count="pageCount" nav-bar="pdfNavigationBar"></pdf-viewer-toolbar><canvas ng-click="next()" id="pdf-canvas" ></canvas></div>',
scope: false,
controller: "PdfCtrl",
link: function(e, t, n) {
e.id = n.delegateHandle, e.showToolbar = e.$eval(n.showToolbar) || !1
var o = n.delegateHandle;
e.currentPage = 1,
e.next = function() {
r.$getByHandle(o).next(), s()
}
var s = function() {
e.currentPage = r.$getByHandle(o).getCurrentPage()
}
}
}
}]);
app.controller('PdfCtrl', [
'$scope',
'$element',
'$attrs',
'pdfDelegate',
'$log',
'$q', '$rootScope',
function($scope, $element, $attrs, pdfDelegate, $log, $q, $rootScope) {
// Register the instance!
var deregisterInstance = pdfDelegate._registerInstance(this, $attrs.delegateHandle);
// De-Register on destory!
$scope.$on('$destroy', deregisterInstance);
var self = this;
var url = $scope.$eval($attrs.url);
var headers = $scope.$eval($attrs.headers);
var pdfDoc;
$scope.pageCount = 0;
var currentPage = 1;
var angle = 0;
var scale = $attrs.scale ? $attrs.scale : 1;
var canvas = $element.find('canvas')[0];
var ctx = canvas.getContext('2d');
self.next = function() {
if (currentPage >= pdfDoc.numPages)
return;
currentPage = parseInt(currentPage, 10) + 1;
renderPage(currentPage);
console.log('currentPage'+currentPage);
};
return PDFJS
.getDocument(docInitParams)
.then(function (_pdfDoc) {
console.log('loaded');
$rootScope.loadPdf = $scope.pdfNavigationBar = true;
pdfDoc = _pdfDoc;
renderPage(1);
$scope.$apply(function() {
$scope.pageCount = _pdfDoc.numPages;
});
}, function(error) {
$log.error(error);
return $q.reject(error);
})
};
if(url) self.load();
}]);
You need to pass the currentPage variable as isolated directive like below.
return {
restrict: "E",
template: '<div class="pdf_navigation" ng-show="navBar">\
<div class="pdf_buttons">\
<div ng-click="prev()" class="goPrevious" title="previous page"></div>\
<div ng-click="next()" class="goNext" id="goNext" title="next page"></div>\
<div ng-click="zoomOut()" class="zoomIn"></div>\
<div ng-click="zoomIn()" class="zoomOut"></div>\
</div>\
<div class="pdf_page">\
<span>Page</span>\
<input type="text" min=1 ng-model="currentPage" maxlength="4" ng-change="goToPage()" >\
<span>of {{pageCount}}</span>\
</div>\
</div>',
scope: {
pageCount: "=",
navBar: "=",
currentPage: "="
},
...
...
...
and now pass that currentPage from pdfViewer directive template like below:
app.angular.module("pdf").directive("pdfViewer", ["pdfDelegate", function(r) {
return {
restrict: "E",
template: '<div show-control class="pdf_doc"><pdf-viewer-toolbar ng-if="showToolbar" delegate-handle="{{id}}" page-count="pageCount" nav-bar="pdfNavigationBar" current-page="currentPage" ></pdf-viewer-toolbar><canvas ng-click="next()" id="pdf-canvas" ></canvas></div>',
scope: false,
controller: "PdfCtrl",
and now define the variable in the scope of the controller PdfCtrl and access from the same.
app.controller('PdfCtrl', [
'$scope',
'$element',
'$attrs',
'pdfDelegate',
'$log',
'$q', '$rootScope',
function($scope, $element, $attrs, pdfDelegate, $log, $q, $rootScope) {
// Register the instance!
var deregisterInstance = pdfDelegate._registerInstance(this, $attrs.delegateHandle);
// De-Register on destory!
$scope.$on('$destroy', deregisterInstance);
var self = this;
var url = $scope.$eval($attrs.url);
var headers = $scope.$eval($attrs.headers);
var pdfDoc;
$scope.pageCount = 0;
$scope.currentPage = 1;
var angle = 0;
var scale = $attrs.scale ? $attrs.scale : 1;
var canvas = $element.find('canvas')[0];
var ctx = canvas.getContext('2d');
self.next = function() {
if ($scope.currentPage >= pdfDoc.numPages)
return;
$scope.currentPage = parseInt($scope.currentPage, 10) + 1;
renderPage($scope.currentPage);
console.log('currentPage'+$scope.currentPage);
};
In your pdfViewerToolbar directive scope is isolated, and if you want change something in that directive you sould pass it as scope element with two way databinding:"=".
scope: {
pageCount: "=",
navBar: "=",
currentPage:"="
}
and use your directive passing controller model like this
<pdf-viewer-toolbar page-count="ctrlModelPageCount" nav-bar="ctrlModelNavBar" current-page="ctrlModelCurrentPage"></pdf-viewer-toolbar>

AngularJS, BootstrapUI : Toggle a button

I have a list of javascript objects I do an ng-repeat on.
I associate each of them a toggle button from UI-Bootstrap.
I want the toggle button to be toggeled depending on the value in my javascript model.
var app = angular.module('App', []);
app.controller('Ctrl', function($scope) {
$scope.list = [{a : '10'},
{a : '20'},
{a : '42'}];
});
<div ng-repeat="data in list">
{{data.a}} <button type="button" class="btn btn-primary" ng-model="data.state" btn-checkbox="">TEST</button>
</div>
http://plnkr.co/edit/JcnzNSKhy68dXtGHlXLe?p=preview
For example, in this case I want the button associated with a = 42 to be already toggeled
Edit : The data from the list are fetched from a GET request so I it's can't be statically written
I'm not sure if this is exactly what you are looking for, but you can add ng-click to the button:
<button type="button" class="btn"
ng-class="{'btn-primary': data.state}"
ng-model="data.state"
ng-click="data.state = !data.state">
TEST
</button>
EDIT
You can set the state in your controller:
var app = angular.module('App', []);
app.controller('Ctrl', function() {
var _this = this;
_this.list = [{a : '10'},
{a : '20'},
{a : '42'}];
var i;
for (i = 0; i < _this.list.length; i++) {
if (_this.list[i].a == 42) {
_this.list[i].state = true;
}
}
});
http://plnkr.co/edit/C8NW5h4pzfzBxrCSntDs?p=preview
While the above answer works, I'd argue that the more Angular approach to this is to use a directive. And it is one less attribute to account for.
html
<button class="btn" nx-toggle ng-model="data.state">toggle</button>
javascript
app.directive('nxToggle', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, elem, attrs, ngModel) {
$scope.$watch(function() {
return ngModel.$modelValue
}, function(val) {
if (val == true)
elem.addClass('btn-primary')
else
elem.removeClass('btn-primary')
})
elem.bind('click', function() {
$scope.$apply(function() {
if (ngModel.$modelValue == true)
ngModel.$setViewValue(false)
else
ngModel.$setViewValue(true)
})
})
}
}
})
http://plnkr.co/edit/bq4roWHUUlaBnj5xr31Z?p=preview

KendoWindow AngularJS: transcluded elements are not shown

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;
});

Resources