I'm looking for a way in angular to tab through hidden inputs. So I have multiple input forms but when not on focus I want them to just display the text. I'm looking for the ability to once I've selected an input to tab through the other inputs even though they are currently hidden.
Any suggestions?
Use Angular directives to make your inputs into inline editors. When the page loads you'll be in display mode (i.e. the display div will be shown and the editor div will be hidden), then on clicking, the mode switches to Edit mode and the visibility is reversed.
Here's a quick snippet of what a DatePicker control would look like when wrapped in such a directive. Using Angular 1 and Bootstrap 3 (follows John Papa's Angular Style Guide):
HTML Template (inlineDatePicker.html):
<div class="inline-edit">
<div ng-if="!vm.inEditMode" data-ng-click="vm.enableEditMode()">
<input type="hidden" data-ng-model="vm.dateModel" data-ng-required="vm.dateRequired" /><span>{{vm.dateModel}}</span> <span class="glyphicon glyphicon-calendar"></span>
</div>
<div ng-if="vm.inEditMode">
<div class="well well-sm" style="position: absolute; z-index: 10">
<datepicker data-ng-model="vm.dateModel" data-show-weeks="false"></datepicker>
<button type="button" class="btn btn-sm btn-info" ng-click="vm.today()">Today</button>
<button type="button" class="btn btn-sm btn-danger" ng-click="vm.cancel()">Cancel</button>
</div>
</div>
</div>
And the underlying directive (inlineDatePicker.directive.js):
(function () {
'use strict';
angular.module('myApp.inlineEdit')
.directive('inlineDatePicker', inlineDatePicker);
function inlineDatePicker() {
'use strict';
inlineDatePickerController.$inject = ['$scope', '$timeout'];
return {
restrict: 'A',
replace: true,
transclude: false,
templateUrl: '/App/inlineEdit/date/inlineDatePicker.html',
scope: {
dateModel: '=',
dateRequired: '#',
dateChanged: '&'
},
controller: inlineDatePickerController,
controllerAs: 'vm',
};
function inlineDatePickerController($scope, $timeout) {
/* jshint validthis:true */
var vm = this;
vm.inEditMode = false;
vm.dateModel = $scope.dateModel;
vm.dateRequired = $scope.$eval($scope.dateRequired);
vm.enableEditMode = enableEditMode;
vm.cancel = cancel;
vm.today = today;
function enableEditMode() {
vm.inEditMode = true;
}
function cancel() {
vm.inEditMode = false;
}
function today() {
vm.dateModel = new Date();
}
$scope.$watch('vm.dateModel', function (curr, orig) {
$scope.dateModel = vm.dateModel;
if (curr != orig && vm.inEditMode) {
$timeout($scope.dateChanged, 0);
}
vm.inEditMode = false;
});
$scope.$watch('dateModel', function () {
vm.dateModel = $scope.dateModel;
});
}
}
})();
Related
I'm not confident what I'm trying to do is correct, so please give me a "more correct" option if the whole premise is wrong.
I have an AngularJS 1.5.11 application. I am trying to create a generic modal html tag that can be used throughout the application wherever a modal is required. I have a page template that looks like this:
<form class="page-sidebar-container" data-name="mainForm">
<div class="page-sections">
<div class="form-columned form-columned-1">
<div class="form-row">
<div class="section column column-0 span-0" id="section-JobFromType">
<h4 class="section-heading">From Type</h4>
<div class="columns gutters-large">
<div style="display: table;margin: 18px 0px;">
<api-select label="Type" items="fromTypeItems" item="selectedFromType" required>
</api-select>
</div>
</div>
</div>
<div class="section column column-1 span-0" id="section-JobToType">
<h4 class="section-heading">To Type</h4>
<div class="columns gutters-large">
<div style="display: table;margin: 18px 0px;">
<api-select label="Type" items="toTypeItems" item="selectedToType"
read-only="toTypeDisabled" required>
</api-select>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<api-modal is-open="entitySelectOpen" label="{{entitySelectLabel}}">
<modal-body>
{{$id}}
<api-select label="{{entitySelectParentLabel}}" items="entitySelectParentItems" item="selectedEntitySelectParent" required>
</api-select>
<api-select label="{{entitySelectChildLabel}}" items="entitySelectChildItems" item="selectedEntitySelectChild" read-only="entitySelectChildDisabled" required>
</api-select>
<api-select label="{{entitySelectEntityLabel}}" items="entitySelectEntityItems" item="selectedEntity" read-only="entitySelectEntityDisabled" required>
</api-select>
</modal-body>
<modal-actions>
{{$id}}
<api-button label="{{modalPrimaryActionLabel}}" type="primary" icon="icon-checkmark" on-click="modalPrimaryActionClick"></api-button>
<api-button label="Return" type="return" icon="icon-cancel" on-click="modalReturnActionClick"></api-button>
</modal-actions>
</api-modal>
with the following controller:
(function (angular) {
angular.module('views.jobcontrol', [
'ngRoute',
'components.formApiControlSelect',
'components.formApiControlText',
'components.formApiModal'
])
.config([
'$routeProvider',
function ($routeProvider) {
'use strict';
var route = {
templateUrl: 'modules/apiViews/jobcontrol/jobcontrol-view.html',
controller: 'JobControlController',
reloadOnSearch: false,
caseInsensitiveMatch: true
};
$routeProvider
.when('/view/jobcontrol/:action/:jobNumber/?', route);
}
]).controller('JobControlController', [
'$scope',
'$timeout',
'$routeParams',
function ($scope, $timeout, $routeParams) {
'use strict';
function generateMockGuid() {
var result, i, j;
result = '';
for (j = 0; j < 32; j++) {
if (j == 8 || j == 12 || j == 16 || j == 20)
result = result + '-';
i = Math.floor(Math.random() * 16).toString(16).toUpperCase();
result = result + i;
}
return result;
function option(label,value){
return {
value:value,
label:label
}
}
$scope.fromTypeItems = [option("test",1)];
$scope.selectedFromType = null;
$scope.$watch('selectedFromType', function (){
console.log("do something");
});
/* to type */
$scope.fromTypeItems = [option("test",1)];
$scope.selectedToType = null;
$scope.toTypeDisabled = true;
$scope.$watch('selectedToType', function () {
console.log("do something else");
});
/* entity select modal */
$scope.selectedFromEntity = null;
$scope.selectedToEntity = null;
$scope.entitySelectParentItems = [option("parent 1", generateMockGuid()),option("parent 2", generateMockGuid()),option("parent 3", generateMockGuid())];
$scope.entitySelectChildItems = [option("child 1", generateMockGuid()),option("child 2", generateMockGuid()),option("child 3", generateMockGuid())];
$scope.entitySelectEntityItems = [option("entity 1", generateMockGuid()),option("entity 2", generateMockGuid()),option("entity 3", generateMockGuid())];
$scope.selectedEntity = null;
$scope.$watch('selectedEntity', function () {
console.log('selectedEntity has changed to ' + $scope.selectedEntity);
});
function clearModalSelections(){
console.log($scope);
$scope.selectedEntitySelectParent = null;
$scope.selectedEntitySelectChild = null;
$scope.selectedEntity = null;
}
$scope.modalPrimaryActionLabel = "Next";
$scope.modalPrimaryActionClick = function(){
clearModalSelections();
$scope.entitySelectOpen = false;
}
$scope.modalReturnActionClick = function(){
clearModalSelections();
$scope.entitySelectOpen = false;
}
}
]);
})(window.angular);
The modal works, it has my api-button's and api-select's in it, and the api-select's items are populated properly with the 3 options added to the $scope.entitySelectParentItems, $scope.entitySelectChildItems and $scope.entitySelectEntityItems arrays. The problem is that
$scope.$watch('selectedEntity', function () {
console.log('selectedEntity has changed to ' + $scope.selectedEntity);
});
never gets called. If I move the three api-select's out of the api-modal > modal-body and up the same level as the api-modal then everything works as expected (other than he elements being on the base page, rather than in the modal), but as soon as everything is inside the modal I lose access to when the user selects a value and what that value is.
I'm sure this must be something to do with the transclude having a seperate scope, but I'm confused. How can the api-select in the modal transclude access the main scope for its items to populate a select list and even updates if the list updates, but when the user selects something it isn't bound back to the scope the same way it does for the other api-select's on the page. Am I using ng-transclude wrong? Is this an OK thing to do, but I am missing a step?
In case it matters, the javascript for api-modal looks like this:
angular.module('components.formApiModal',[
'components.formApiButton'
])
.directive('apiModal', ['$timeout', '$compile', function ($timeout, $compile) {
'use strict';
return {
restrict: 'E',
templateUrl: 'modules/apiComponents/generic/modal/modal-template.html',
controller: 'apiModalController',
transclude: {
'body': 'modalBody',
'actions': 'modalActions'
},
scope: {
isOpen: "=",
label: '#',
actions: "="
},
link: function (scope, element, attrs) {
}
};
}])
.controller('apiModalController', ['$scope', function($scope) {
}]);
and the template:
<div class="modal-backdrop modal-large" data-ng-class="{'modal-closed' : !isOpen }">
<div class="modal-container">
<div class="modal" data-ng-click="$event.stopPropagation()">
<h1 class="modal-header" >{{label}}</h1>
<div class="modal-body">
<div class="form-messages" data-ng-if="formPage.overrideConfirmationMessages.length">
<div class="form-header-errors">
</div>
</div>
<h4 class="section-heading" data-ng-if="section.altHelp">{{section.altHelp}}</h4>
<div class="columns gutters-large">
<div ng-transclude="body"></div>
</div>
</div>
<div class="modal-footer" >
<div ng-transclude="actions"></div>
</div>
</div>
</div>
</div>
I have this problem in my app, when I use slice to remove the user from the list. However, it does not remove from the list. I am getting the user with a API url call. But for some reason, it does not remove the user from the list. Please, have a look at my code. If, you guys want the full code, I have put it in my github. I hope we both can solve this. Thank you in advance.
Here is my code:
<div ng-controller="MyCtrl">
<div ng-repeat="person in userInfo.lawyers | filter : {id: lawyerId}">
<a class="back" href="#/lawyer">Back</a>
<button type="button" class="edit" ng-show="inactive" ng-click="inactive = !inactive">
Edit
</button>
<button type="submit" class="submit" ng-show="!inactive" ng-click="inactive = !inactive">Save</button>
<a class="delete" ng-click="confirmClick(); confirmedAction(person);" confirm-click>Confirm</a>
<div class="people-view">
<h2 class="name">{{person.firstName}}</h2>
<h2 class="name">{{person.lastName}}</h2>
<span class="title">{{person.email}}</span>
<span class="date">{{person.website}} </span>
</div>
<div class="list-view">
<form>
<fieldset ng-disabled="inactive">
<legend>Basic Info</legend>
<b>First Name:</b>
<input type="text" ng-model="person.firstName">
<br>
<b>Last Name:</b>
<input type="text" ng-model="person.lastName">
<br>
<b>Email:</b>
<input type="email" ng-model="person.email">
<br>
<b>Website:</b>
<input type="text" ng-model="person.website">
<br>
</fieldset>
</form>
</div>
</div>
</div>
App.js
var app = angular.module("Portal", ['ngRoute', 'ui.bootstrap' ]);
app.controller('MyCtrl', function($scope, $window) {
$scope.inactive = true;
$scope.confirmedAction = function (lawyer) {
$scope.$apply(function () {
var index = $scope.userInfo.lawyers.indexOf(lawyer);
console.log($scope.userInfo.lawyers);
$scope.userInfo.lawyers.splice(index, 1);
console.log($scope.userInfo.lawyers);
$window.location.href = '#/lawyer';
});
};
});
app.directive('confirmClick', ['$q', 'dialogModal', function($q, dialogModal) {
return {
link: function (scope, element, attrs) {
// ngClick won't wait for our modal confirmation window to resolve,
// so we will grab the other values in the ngClick attribute, which
// will continue after the modal resolves.
// modify the confirmClick() action so we don't perform it again
// looks for either confirmClick() or confirmClick('are you sure?')
var ngClick = attrs.ngClick.replace('confirmClick()', 'true')
.replace('confirmClick(', 'confirmClick(true,');
// setup a confirmation action on the scope
scope.confirmClick = function(msg) {
// if the msg was set to true, then return it (this is a workaround to make our dialog work)
if (msg===true) {
return true;
}
// msg can be passed directly to confirmClick('Are you sure you want to confirm?')
// in ng-click
// or through the confirm-click attribute on the
// <a confirm-click="Are you sure you want to confirm?"></a>
msg = msg || attrs.confirmClick || 'Are you sure you want to confirm?';
// open a dialog modal, and then continue ngClick actions if it's confirmed
dialogModal(msg).result.then(function() {
scope.$eval(ngClick);
});
// return false to stop the current ng-click flow and wait for our modal answer
return false;
};
}
}
}])
/*
Modal confirmation dialog window with the UI Bootstrap Modal service.
This is a basic modal that can display a message with yes or no buttons.
It returns a promise that is resolved or rejected based on yes/no clicks.
The following settings can be passed:
message the message to pass to the modal body
title (optional) title for modal window
okButton text for YES button. set false to not include button
cancelButton text for NO button. ste false to not include button
*/
.service('dialogModal', ['$modal', function($modal) {
return function (message, title, okButton, cancelButton) {
// setup default values for buttons
// if a button value is set to false, then that button won't be included
cancelButton = cancelButton===false ? false : (cancelButton || 'No');
okButton = okButton ===false ? false : (okButton || 'Yes');
// setup the Controller to watch the click
var ModalInstanceCtrl = function ($scope, $modalInstance, settings) {
// add settings to scope
angular.extend($scope, settings);
// yes button clicked
$scope.ok = function () {
// alert("Lawyer is confirmed");
$modalInstance.close(true);
};
// no button clicked
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
// open modal and return the instance (which will resolve the promise on ok/cancel clicks)
var modalInstance = $modal.open({
template: '<div class="dialog-modal"> \
<div class="modal-header" ng-show="modalTitle"> \
<h3 class="modal-title">{{modalTitle}}</h3> \
</div> \
<div class="modal-body">{{modalBody}}</div> \
<div class="modal-footer"> \
<button class="btn btn-primary" ng-click="ok()" ng-show="okButton">{{okButton}}</button> \
<button class="btn btn-warning" ng-click="cancel()" ng-show="cancelButton">{{cancelButton}}</button> \
</div> \
</div>',
controller: ModalInstanceCtrl,
resolve: {
settings: function() {
return {
modalTitle: title,
modalBody: message,
okButton: okButton,
cancelButton: cancelButton
};
}
}
});
// return the modal instance
return modalInstance;
}
}])
app.config(function ($routeProvider) {
$routeProvider
.when("/lawyer", {
controller: "HomeController",
templateUrl: "partials/home.html"
})
.when("/lawyer/:id", {
controller: "LawyerController",
templateUrl: "partials/about.html"
})
.otherwise({
redirectTo: '/lawyer'
});
});
But the element is getting deleted from list right?
If yes then, Try this :
$scope.confirmedAction = function (lawyer) {
$scope.$apply(function () {
var index = $scope.userInfo.lawyers.indexOf(lawyer);
console.log($scope.userInfo.lawyers);
$scope.userInfo.lawyers.splice(index, 1);
console.log($scope.userInfo.lawyers);
$window.location.href = '#/lawyer';
});
});
Or
$scope.confirmedAction = function (lawyer) {
$timeout(function () {
var index = $scope.userInfo.lawyers.indexOf(lawyer);
console.log($scope.userInfo.lawyers);
$scope.userInfo.lawyers.splice(index, 1);
console.log($scope.userInfo.lawyers);
$state.go($state.current, {}, {reload: true});
// $window.location.href = '#/lawyer';
},1100);
});
The problem is that you don't get the index from IndexOf when you using it on an array of objects like you do. Read more about the IndexOf here.
Instead, use map and then use IndexOf on that
Try it like this:
$scope.confirmedAction = function (lawyer) {
var index = $scope.userInfo.lawyers.map(function(e) { return e.id; }).indexOf(lawyer.id);
$scope.userInfo.lawyers.splice(index, 1);
console.log($scope.userInfo.lawyers);
$window.location.href = '#/lawyer';
};
And also, the controller changes will by default be detected by the digest loop of angular so no need to use $scope.$apply.
Also, simplifyed your plunker with the basic get array list and remove function. Use that to build your way forvered
https://plnkr.co/edit/w6NuVLcqzc5Rjs7L6Cox?p=preview
I'm new to AngularJS and using UI Bootstrap in a project. I want to mark an I've read the T&Cs checkbox as checked once the modal (containing the T&Cs text) is closed (but not when the modal is dismissed).
I've adapted the general example at https://angular-ui.github.io/bootstrap/ but having issues updating the scope / view with the value of $scope.accept_terms.
I have the modal opening / closing fine, but the checkbox always remains unchecked.
HTML:
<form>
<div class="checkbox">
<input type="checkbox" id="user_details_termsConditions"
name="user_details[termsConditions]"
required="required" ng-checked="accept_terms" />
<label for="user_details_termsConditions" >I agree to the terms and conditions</label>
</div>
</form>
JS:
angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($uibModal, $log, $document, $scope) {
var $ctrl = this;
$ctrl.animationsEnabled = true;
$ctrl.open = function (size, parentSelector) {
var parentElem = parentSelector ?
angular.element($document[0].querySelector('.container ' + parentSelector)) : undefined;
var modalInstance = $uibModal.open({
animation: $ctrl.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
controllerAs: '$ctrl',
size: size,
appendTo: parentElem
});
modalInstance.result.then(function (result) {
$scope.accept_terms = result;
$log.info('accept_terms = ' + $scope.accept_terms);
// prints accept_terms = 1
}, function () {
});
};
});
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($uibModalInstance) {
var $ctrl = this;
$ctrl.ok = function () {
$uibModalInstance.close(true);
};
});
Can anyone point me in the right direction?
Turns out this was a simple matter of using ng-model on the checkbox instead of ng-checked:
Controller:
modalInstance.result.then(function (result) {
$scope.accept_terms = true;
}, function () {
});
Markup:
<input type="checkbox" id="user_details_termsConditions"
name="user_details[termsConditions]" required="required"
ng-model="accept_terms" value="1" />
I am very new to front-end development and I thought it would be cool to add drag and drop to a current upload page. However after starting to hook everything up with ng-flow (a directive that assists with drag and drop) I cannot seem to make the connection on how to add the files to the file list. If you think I don't even need the directive and am just overkilling this and there is a simpler solution I would be willing to make changes as well. NOTE: I am giving only samples of the code so dont ding it for not compiling!
fileModelDirective:
app.directive('fileModel', ['$parse', '$log', '$confirm',
function ($parse, $log, $confirm) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
scope.sampleFile = model;
element.bind('change', function () {
// if the file open dialog is raised and the file name
// is cleared and cancel is pressed then a reset is needed
// document.getElementById('file-upload-name').innerHTML = "";
// document.getElementById('file-upload-btn').disabled = true;
// status always needs reset if choosing another file
scope.$apply(function () {
modelSetter(scope, element[0].files);
if (document.getElementById('file-upload').files) {
// This iterates over to see if the total files size is greater than 100MB
const maxFilesSize = 104857600;
var totalFilesSize = 0;
var numberOfDataSamples = element[0].files.length;
}
});
});
} // link
};
}]); // fileModel
fileMethod
$scope.uploadFile = function () {
console.log(flow)
var file = flow.file;
$scope.numberOfFiles = document.getElementById('file-upload').files.length;
$scope.filesTotalSize = 0;
for (var i = 0; i < document.getElementById('file-upload').files.length; i++) {
$scope.filesTotalSize = document.getElementById('file-upload').files[i].size + $scope.filesTotalSize;
}
fileUpload Service
app.service('fileUpload', ['$http', '$log',
function ($http, $log) {
this.uploadFileToUrl = function (file, uploadUrl) {
//$log.debug("file(s)");
//$log.debug(file);
var fd = new FormData();
angular.forEach(file, function (value, key) {
fd.append(key, value);
});
return $http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined,
'enctype': "multipart/form-data"
}
})
}; // uploadFileToUrl
}]); // fileUpload
html
<div flow-init flow-files-submitted="$flow.upload()" class="ng-scope">
<div flow-drop>
<span for="file-upload"
class="btn btn-primary" flow-btn style="margin-top: 10px; ">Upload File
<input id="file-upload" type="file" multiple="multiple" file-model="sampleFile"
style="visibility: hidden; position: absolute;"></span>
<p flow-prevent-drop
flow-drag-enter="style={border: '5px dashed purple'}"
flow-drag-leave="style={}"
ng-style="style"
style="margin-top: 10px;width: 100%;min-height: 50px;">
Drag And Drop your file here</p>
<br>
<span ng-repeat="file in $flow.files track by $index">
{{file.name + ", " }}
</span>
<div style="margin-left: 2px; margin-top: 10px;">
<button id="file-upload-btn" class="btn btn-primary"
ng-click="showMask(); uploadFile();">
Upload
</button>
<button class="btn btn-primary" style="float: right;"
ng-click="navigateTo('/startup')">
Cancel
</button>
<button style="float: right; margin-right: 6px;" class="btn btn-primary"
ng-click="$flow.cancel()">
Clear
</button>
</div>
</div>
</div>
I'm just experimenting with a similar service. Taking angular Array of files, and pushing the items onto the javascript "file-upload".FileList array, but no luck, as the 'files' property is a readonly FileList object.
A pre-packaged solution:
http://blueimp.github.io/jQuery-File-Upload/angularjs.html
and it has drag and drop on to the whole page working.
This one: http://angular-file-upload.appspot.com/ even has Paste and access to Camera on mobile.
Your solution for adding files to the formData is good and inline with jquery ajaxSubmit form code
Maybe you could create a Plnk to collaborate on ...
formdata.append(a[i].name, a[i].value);
I want to use a directive to customize my code.
I have created a button to switch isCollapsedUpload flag defined in the controller as: #scope.isCollapsedUpload=false.
When the user presses the button, the isCollapsedUpload turns to true or vice versa and the icon changes.
From the controller:
$scope.switcher = function (booleanExpr, trueValue, falseValue) {
return booleanExpr ? trueValue : falseValue;
}
$scope.isCollapsedUpload = false;
<button class="btn" ng-click="isCollapsedUpload = !isCollapsedUpload">
<span>Upload file</span>
<i class="{{ switcher( isCollapsedUpload, 'icon-chevron-right', 'icon-chevron-down' )}}"></i>
</button>
I wrote this directive:
feederliteModule.directive('collapseExtend', function() {
return {
restrict: 'E',
scope: { isCollapsed:'#collapseTarget' },
compile: function(element, attrs)
{
var htmlText =
'<button class="btn" ng-click="isCollapsed = !isCollapsed">'+
' <span>'+attrs.label+'</span>'+
' <i class="{{ switcher(isCollapsed, \'icon-chevron-right\', \'icon-chevron-down\' )}}"></i>'+
'</button>';
element.replaceWith(htmlText);
}
}
});
And now I can use it like:
<collapse-extend
collapse-target="isCollapsedUpload"
label="Upload file"
></collapse-extend>
It doesn't work. No icon changes. No errors,
isCollapsedUpload flag doesn't change. It changes only into directive
Did I miss something?
The reason the class doesn't change correctly is because you are not linking the template properly. This is easy to fix if you use the built in functionality:
var feederliteModule = angular.module('feederliteModule', []);
feederliteModule.directive('collapseExtend', [function() {
return {
restrict: 'E',
scope: {
isCollapsed:'=collapseTarget',
label: '#'
},
template: '<button class="btn" ng-click="isCollapsed = !isCollapsed">'+
'<span>{{ label }}</span>'+
'<i ng-class="{ \'icon-chevron-right\': isCollapsed, \'icon-chevron-down\': !isCollapsed }"></i>'+
'</button>'
}
}]);
feederliteModule.controller('test', ['$scope', function($scope) {
$scope.isCollapsedUpload = false;
}]);
To the best of my understanding, by replacing the parent element, you were removing the isolate scope this object was tied to without creating a new one on the button itself.
EDIT: See a complete working fiddle with multiple buttons
I suggest using a service instead of a controller to maintain your model data. This allows you better separation of concerns as your app gets more complex:
var feederliteModule = angular.module('feederliteModule', []);
feederliteModule.service('btnService', function(){
this.isCollapsedUpload = false;
this.isCollapsedSomething = false;
});
feederliteModule.controller('btnController', function($scope, btnService){
$scope.isCollapsedUpload = btnService.isCollapsedUpload;
$scope.isCollapsedSomething = btnService.isCollapsedSomething;
});
feederliteModule.directive('collapseExtend', function() {
return {
restrict: 'E',
scope: {
isCollapsed:'=collapseTarget',
label:'#'
},
replace: true,
link: function (scope, element, attrs){
scope.switcher = function (booleanExpr, trueValue, falseValue) {
return booleanExpr ? trueValue : falseValue;
};
scope.toggleCollapse = function() {
scope.isCollapsed = !scope.isCollapsed;
}
},
template: '<button class="btn" ng-click="toggleCollapse()">'+
'<span>{{label}}</span>'+
'<i ng-class="switcher(isCollapsed, \'icon-chevron-right\', \'icon-chevron-down\')"></i>'+
'</button>'
}
});
Also, notice that you must use '=' instead of '#' in order for isCollapsed to work as you expect. The answer above needs this as well.