AngularJS - Scope Not Updating - angularjs

For some reason, I can't remove the description and packing elements/fields (see picture) from the scope variable, even after deleting their respective code and restarting the application. Any help is much appreciated.
My directive:
app.directive('formElement', function() {
return {
restrict: 'E',
transclude: true,
scope: {
label : "#",
model : "="
},
link: function(scope, element, attrs) {
scope.disabled = attrs.hasOwnProperty('disabled');
scope.required = attrs.hasOwnProperty('required');
scope.pattern = attrs.pattern || '.*';
console.log(element);
},
template:
'<div class="form-group">' +
'<label class="col-sm-3 control-label no-padding-right"> {{label}}</label>' +
'<div class="col-sm-7">' +
'<span class="block input-icon input-icon-right" ng-transclude></span>' +
'</div></div>'
};
});
My controllers:
app.controller('ProductsCtrl', function ($scope, $modal, $filter, Data) {
$scope.product = {};
Data.get('products').then(function(data){
$scope.products = data.data;
});
$scope.changeProductStatus = function(product){
product.status = (product.status=="Active" ? "Inactive" : "Active");
Data.put("products/"+product.id,{status:product.status});
};
$scope.deleteProduct = function(product){
if(confirm("Are you sure to remove the product?")){
Data.delete("products/"+product.id).then(function(result){
$scope.products = _.without($scope.products, _.findWhere($scope.products, {id:product.id}));
});
}
};
$scope.open = function (p,size) {
var modalInstance = $modal.open({
templateUrl: 'partials/product-edit.html',
controller: 'ProductEditCtrl',
size: size,
resolve: {
item: function () {
return p;
}
}
});
modalInstance.result.then(function(selectedObject) {
if(selectedObject.save == "insert"){
$scope.products.push(selectedObject);
$scope.products = $filter('orderBy')($scope.products, 'id', 'reverse');
}else if(selectedObject.save == "update"){
p.price = selectedObject.price;
p.stock = selectedObject.stock;
}
});
};
$scope.columns = [
{text:"ID",predicate:"id",sortable:true,dataType:"number"},
{text:"Name",predicate:"name",sortable:true},
{text:"Price",predicate:"price",sortable:true},
{text:"Stock",predicate:"stock",sortable:true},
{text:"Status",predicate:"status",sortable:true},
{text:"Action",predicate:"",sortable:false}
];
});
app.controller('ProductEditCtrl', function ($scope, $modalInstance, item, Data) {
$scope.product = angular.copy(item);
$scope.cancel = function () {
$modalInstance.dismiss('Close');
};
$scope.title = (item.id > 0) ? 'Edit Product' : 'Add Product';
$scope.buttonText = (item.id > 0) ? 'Update Product' : 'Add New Product';
var original = item;
$scope.isClean = function() {
return angular.equals(original, $scope.product);
};
$scope.saveProduct = function (product) {
product.uid = $scope.uid;
if(product.id > 0){
Data.put('products/'+product.id, product).then(function (result) {
if(result.status != 'error'){
var x = angular.copy(product);
x.save = 'update';
$modalInstance.close(x);
}else{
console.log(result);
}
});
}else{
product.status = 'Active';
Data.post('products', product).then(function (result) {
if(result.status != 'error'){
var x = angular.copy(product);
x.save = 'insert';
x.id = result.data;
$modalInstance.close(x);
}else{
console.log(result);
}
});
}
};
});
HTML:
product-edit.html (partial):
<div class="modal-header">
<h3 class="modal-title">Edit product [ID: {{product.id}}]</h3>
</div>
<div class="modal-body">
<form name="product_form" class="form-horizontal" role="form" novalidate>
<form-element label="NAME" mod="product">
<input type="text" class="form-control" name="name" placeholder="Name" ng-model="product.name" ng-disabled="product.id" focus/>
</form-element>
<form-element label="PRICE" mod="product">
<input type="text" name="price" class="form-control" placeholder="PRICE" ng-model="product.price" only-numbers/>
<small class="errorMessage" ng-show="product_form.price.$dirty && product_form.price.$invalid"> Enter the price.</small>
</form-element>
<form-element label="STOCK" mod="product">
<input type="text" name="stock" class="form-control" placeholder="STOCK" ng-model="product.stock" only-numbers/>
<small class="errorMessage" ng-show="product_form.stock.$dirty && product_form.stock.$invalid"> Enter the available stock.</small>
</form-element>
<div class="modal-footer">
<form-element label="">
<div class="text-right">
<a class="btn btn-sm" ng-click="cancel()">Cancel</a>
<button ng-click="saveProduct(product);"
ng-disabled="product_form.$invalid || enableUpdate"
class="btn btn-sm btn-primary"
type="submit">
<i class="ace-icon fa fa-check"></i>{{buttonText}}
</button>
</div>
</form-element>
</div>
</form>
</div>
products.html (partial):
<div class="panel panel-default">
<div class="panel-heading" style="height: 60px;">
<div class="pull-left">
<input placeholder="Filter inventory list ..." class="form-control" aria-describedby="basei" ng-model="filterProduct" ng-change="resetLimit();" autocomplete="off" type="text" focus>
</div>
<div class="pull-right">
<button type="button" class="btn btn-default fa fa-plus" ng-click="open(product);">Add New Product</button>
</div>
</div>
<div class="panel-body">
<div class="input-group pull-right">
</div>
<table class="table table-striped">
<tr ng-show="products.length==0"><td style="vertical-align:middle;"><i class="fa fa-ban fa-3x"></i> No data found</td></tr>
<tr ng-hide="products.length>-1"><td style="vertical-align:middle;"><i class="fa fa-spinner fa-spin"></i> Loading</td></tr>
<tr><th ng-repeat="c in columns">{{c.text}}</th></tr>
<tr ng-repeat="c in products | filter:filterProduct | orderBy:'-id'" id="{{c.id}}" animate-on-change='c.stock + c.price' ng-animate=" 'animate'">
<td>{{c.id}}</td><td>{{c.name}}</td><td>{{c.price}}</td><td>{{c.stock}}</td>
<td>
<button class="btn" ng-class="{Active:'btn-success', Inactive:''}[c.status]" ng-click="changeProductStatus(c);">{{c.status}}</button>
</td>
<td>
<div class="btn-group">
<button type="button" class="btn btn-default fa fa-edit" ng-click="open(c);"></button>
<button type="button" class="btn btn-danger fa fa-trash-o" ng-click="deleteProduct(c);"></button>
</div>
</td>
</tr>
</table>
</div>
</div>

I often have a problem with my templates being cached while using Angular. In chrome if you have the developer console open you can go to settings and prevent it from using cached results while the console is open. Or clear your browser cache manually

Related

AngularJS: Passing data to modal from list

I am currently learning how to build a MEAN webapp from scratch. Stuff goes quite well until this point but now i am stuck at trying to pass data from my list (ng-repeat) to my modal via ng-click=updatePerson(person). I have absolutely no clue why I can't access the data from the list. I tried like 20 variants to link the data between both scopes without any success.
This is my Controller:
angular.module('userCtrl', ['userService','ui.bootstrap'])
.controller( 'userController', function(User, $uibModal, $log, $scope) {
var vm = this;
User.all().success( function(data) {
vm.users = data;
})
vm.deleteUser = function(id) {
User.delete(id).success(function(data) {
User.all().success(function(data) {
vm.users = data;
});
});
};
vm.createUser = function() {
User.create(vm.userData).success(function(data) {
vm.userData = {};
User.all().success(function(data) {
vm.users = data;
});
});
};
vm.updateUser = function(selectedUser) {
$scope.selectedUser = selectedUser;
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'app/views/pages/modal.html',
resolve: {
user: function () {
return $scope.selectedUser;
}
}
});
modalInstance.result.then(function(selectedUser) {
$scope.selected = selectedUser;
});
};
});
My angular-router:
angular.module('appRoutes', ['ngRoute'])
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl : 'app/views/pages/home.html',
controller : 'userController',
controllerAs : 'user'
})
.when('/users', {
templateUrl : 'app/views/pages/user.html',
controller : 'userController',
controllerAs : 'user'
});
$locationProvider.html5Mode(true);
});
My list:
<div class="btn-group">
<button type="button" class="btn-lg btn-default glyphicon glyphicon-plus" data-toggle="modal" data-target="#createModal"></button>
<table class="table table-nonfluid table-bordered table-striped" ng-show="user.users">
<thead>
<tr>
<th></th>
<th>Vorname</th>
<th>Nachname</th>
<th>E-Mail</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="person in user.users">
<td><button ng-click="user.deleteUser(person._id)" class="btn btn-default btn-lg glyphicon glyphicon-trash"></button></td>
<td>{{person.firstname}}</td>
<td>{{person.lastname}}</td>
<td>{{person.mail}}</td>
<td><button ng-click="user.updateUser(person)" class="btn btn-default btn-lg glyphicon glyphicon-trash"></button></td>
<!--<td><button class="btn-lg btn-default glyphicon glyphicon-option-horizontal" data-toggle="modal" data-target="#updateModal"></button> </td>-->
</tr>
</tbody>
</table>
<!--Create Modal-->
<div class="modal fade bs-example-modal-lg" id="createModal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="exampleModalLabel">Neue Person</h4>
</div>
<form id="form1" ng-submit="user.createUser()">
<div class="modal-body">
<div class="form-group">
<label for="recipient-name" class="control-label">Vorname</label>
<input type="text" class="form-control" ng-model="user.userData.firstname">
</div>
<div class="form-group">
<label for="recipient-name" class="control-label">Nachname</label>
<input type="text" class="form-control" ng-model="user.userData.lastname">
</div>
<div class="form-group">
<label for="recipient-name" class="control-label">E-Mail</label>
<input type="text" class="form-control" ng-model="user.userData.mail">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Schließen</button>
<button id="button1" type="submit" class="btn btn-primary">Person erstellen</button>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$('#button1').click(function() {
$('#createModal').modal('hide');
});
</script>
And here is my modal:
<div class="modal-content bs-example-modal-lg" role="dialog document">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="exampleModalLabel">Ändere Person</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="recipient-name" class="control-label">Vorname</label>
<input type="text" class="form-control" ng-model="person.firstname" placeholder={{person.firstname}}>
</div>
<div class="form-group">
<label for="recipient-name" class="control-label">Nachname</label>
<input type="text" class="form-control" ng-model="person.firstname" placeholder={{person.lastname}}>
</div>
<div class="form-group">
<label for="recipient-name" class="control-label">E-Mail</label>
<input type="text" class="form-control" ng-model="person.firstname" placeholder={{person.mail}}>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Schließen</button>
<button id="button1" type="submit" class="btn btn-primary">Person ändern</button>
</div>
</div>
The user you're resolving won't be bound to the view automatically. You need a controller to do that. You can use the code below, or you can use controllerAs, but you'd have to update the modal's HTML accordingly.
vm.updateUser = function(selectedUser) {
$scope.selectedUser = selectedUser;
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'app/views/pages/modal.html',
resolve: {
user: function () {
return $scope.selectedUser;
}
},
controller: function($scope, user) {
$scope.user = user;
}
});
modalInstance.result.then(function(selectedUser) {
$scope.selected = selectedUser;
});
};

Bootstrap modal form elements unfocussable (on mobile/mobile emulation)

From the repo: https://github.com/jmsherry/kitchenapp
Live at: https://kitchenapp2.herokuapp.com
If you click the 'contact us' link in the bottom right corner of the screen a modal appears. The modal is coded like:
<div class="modal-container">
<button type="button" class="close" aria-label="Close" ng-click="$close(null)">
<span aria-hidden="true">×</span>
</button>
<div class="content">
<h1>Contact Us</h1>
<div class="contact-form">
<form ng-submit="vm.sendMessage(this)" novalidate name="contactForm">
<div class="form-group" ng-if="vm.user && vm.user.email">
<p class="faux-label">From: <span class="faux-value">{{vm.user.email}}</span></p>
</div>
<div class="form-group" ng-class="{ 'has-error' : contactForm.from.$invalid && !contactForm.from.$pristine }" ng-if="!vm.user || !vm.user.email">
<label for="subject">From</label>
<input type="email" name="from" id="from" class="form-control" placeholder="From" ng-model="vm.user.email" ng-maxlength="30" ng-required="true" autofocus>
<ul ng-if="contactForm.from.$invalid && !contactForm.from.$pristine" ng-messages="contactForm.from.$error" class="help-block list-unstyled">
<li ng-message="maxlength">The subject must be less than 30 characters.</li>
<li ng-message="email">Not a valid email. Please check carefully and try again...</li>
</ul>
</div>
<div class="form-group" ng-class="{ 'has-error' : contactForm.subject.$invalid && !contactForm.subject.$pristine }">
<label for="subject">Subject</label>
<input type="text" name="subject" id="subject" class="form-control" placeholder="Subject" ng-model="vm.email.subject" ng-maxlength="30">
<ul ng-if="contactForm.subject.$invalid && !contactForm.subject.$pristine" ng-messages="contactForm.subject.$error" class="help-block list-unstyled">
<li ng-message="maxlength">The subject must be less than 30 characters.</li>
</ul>
</div>
<div class="form-group" ng-class="{ 'has-error' : contactForm.message.$invalid && !contactForm.message.$pristine }">
<label for="message">Message</label>
<textarea name="message" id="message" class="form-control" placeholder="Message..." ng-model="vm.email.body" ng-required="true" ng-minlength="10" ng-maxlength="500"></textarea>
<ul ng-if="contactForm.message.$invalid && !contactForm.message.$pristine" ng-messages="contactForm.message.$error" class="help-block list-unstyled">
<li ng-message="required">A description is required.</li>
<li ng-message="minlength">The name must be longer than 10 characters.</li>
<li ng-message="maxlength">The name must be less than 500 characters.</li>
</ul>
</div>
<!-- <div class="form-group"> -->
<div class="checkbox">
<label for="cc_self">
<input type="checkbox" id="cc_self" name="cc_self" ng-model="vm.email.cc_self">Send a copy to my email.
</label>
</div>
<!-- </div> -->
<div class="form-group">
<div class="pull-right">
<button type="button" class="btn btn-default" ng-click="$close(null)">Cancel</button>
<button type="submit" class="btn btn-primary" ng-disabled="contactForm.$invalid">Send</button>
</div>
</div>
</form>
</div>
</div>
</div>
Controller looks like:
angular.module('kitchenapp.directives')
.controller('KaFooterCtrl', ['$scope', '$q', '$log', '$modal', 'Email', 'Auth', 'toastr', function ($scope, $q, $log, $modal, Email, Auth, toastr) {
var vm = this,
$user;
function contact(day) {
$log.log('contact fn', arguments);
$modal.open({
templateUrl: '/views/modals/contact-modal.html',
controller: function modalController($modalInstance, $scope) {
$scope.vm = this;
$scope.vm.email = vm.email;
$scope.vm.user = vm.user;
$scope.vm.sendMessage = function () {
$modalInstance.close();
$q.when(vm.user, function (user) {
var $emailSent = Email.sendEmail(vm.email, vm.user);
$q.when($emailSent, function (res) {
toastr.success('Email sent! Thank you for your interest...');
}, function () {
toastr.error('We\'re sorry your email hasn\'t been sent, please try again later...');
});
});
event.preventDefault();
event.stopPropagation();
};
},
contollerAs: 'vm'
});
}
vm.year = new Date().getFullYear();
vm.email = {};
$user = Auth.getUser();
$q.when($user, function (user) {
vm.user = user;
});
vm.contact = contact;
vm.name = 'KaFooterCtrl';
}])
.directive('kaFooter', function () {
return {
restrict: 'E',
replace: true,
templateUrl: 'directives/footer/footer.html',
scope: {
companyName: '#',
companyEmail: '#'
},
controller: 'KaFooterCtrl as vm',
bindToController: true
};
});
}());
For some reason the first element focusses once, but any further interaction and the elements are not focussable by touch or mouse. Any clues why?
Thanks
So, it transpires that this is a problem when ng-touch is used. ng-touch auto-blurs the fields (https://github.com/angular/angular.js/pull/11212). A fix is on the way, but for now the user #jdhiro suggests using a directive to stop propagation of the touchend event outside of your modal. See https://github.com/angular-ui/bootstrap/issues/2017#issuecomment-39515923 for more

Angular filter on multiple array keys

Here is my code,
(function (module) {
module.controller('TemplatesController', function (Template) {
var model = this;
model.loading = false;
model.templates = [];
model.attributes = [];
model.categories = [];
model.media = [];
init();
function init() {
getTemplates();
}
function getTemplates() {
model.loading = true;
Template.types.query().$promise.then(function (response) {
model.media = response.media;
});
Template.categories.query().$promise.then(function (response) {
model.categories = response.categories;
});
Template.attributes.query().$promise.then(function (response) {
model.attributes = response.attributes;
});
Template.templates.query().$promise.then(function (response) {
model.templates = response.templates;
});
model.loading = false;
}
model.filteredTemplates = function () {
return model.templates.filter(function (template) {
return model.filterBy.indexOf(template.media_category.id) !== -1;
});
};
});
}(angular.module("adbuilder.dealer.templates")));
and html
<div class="filters">
<h4 class="product-filters">Filter Category</h4>
<div data-toggle="buttons">
<label class="btn btn-default btn-block"
ng-repeat="category in templates.categories"
ng-class="{'active': category.isChecked}">
<input type="checkbox" value="{{ category.id}}" ng-model="category.isChecked">
{{ category.name}}
</label>
</div>
<hr>
<h4 class="product-filters">Media</h4>
<div data-toggle="buttons">
<label class="btn btn-default btn-block"
ng-repeat="media in templates.media"
ng-class="{'active': media.isChecked}">
<input type="checkbox" value="{{ media.id}}" ng-model="media.isChecked">
{{ media.name}}
</label>
</div>
<hr>
<h4 class="product-filters">Type</h4>
<div data-toggle="buttons">
<label class="btn btn-default btn-block"
ng-repeat="attribute in templates.attributes"
ng-class="{'active': attribute.isChecked}">
<input type="checkbox" value="{{ attribute.id}}" ng-model="attribute.isChecked">
{{ attribute.name}}
</label>
</div>
</div>
<div ng-repeat="template in filteredTemplates(templates.templates)" class="col-md-4 col-sm-6 m-item">
I have array of checkbox, in model.attributes, model.categories and
model.media. Now I want to filter templates to view only selected.
template.media_category.id contains category id
template.media_type.id contains type id
template.media_type_attribute_options.media_type_attribute_id contains atribute id
How to make it works? Currently it returns nothing..

AngularJS - ng-disabled directive acting weird

I'm using few modals in my angular project, in every modal which is a form I'm using button with ng-disabled directive and each modal has its own controller.
The issue is that when I debugging the code I can see that when I'm opening one modal the debugger run on all the ng-disabled directives in the code although it should run only on the ng-disabled function in the current modal that I use.
On each ng-disabled I run some verification function in its own controller,
like ng-disabled='somefunction()'
and somefunction() in the controller is somefunction() = x || y;
Do I miss something ?
controller:
app.controller('NewHolidayModalController', function ($scope, close, HolidaysService) {
var centerList = $scope.$parent.$$childHead.centers;
var currCenterDN = $scope.$parent.$$childHead.currentCenter.DN;
var indexOfCurrentCenter = _.indexOf(_.pluck(centerList, 'DN'), currCenterDN);
centerList[indexOfCurrentCenter].ticked = true;
var selectedDNs;
$scope.dt = k = new Date();
$scope.close = function (result) {
centerList[indexOfCurrentCenter].ticked = false;
close(result, 500);
};
$scope.conditionsForSendNewHoliday = function () {
selectedDNs = _.select(centerList, { ticked: true });
return (($scope.starttime >= $scope.endtime) || ($scope.dt < k) || (angular.isDate($scope.dt) == false) || (angular.isDate($scope.starttime) == false) || (angular.isDate($scope.endtime) == false) || ($scope.HolidayName.length == 0) || (selectedDNs.length == 0));
};
$scope.addHoliday = function () {
holiday = HolidaysService.formatDateAndTime($scope);
for (i = 0; i < selectedDNs.length; i++)
{
newHoliday = { DN: selectedDNs[i].DN, HolidayName: $scope.HolidayName, HolidayDate: holiday.Date, BeginHour: holiday.start, EndHour: holiday.end }
HolidaysService.addHoliday(newHoliday)
.success(function (data, status, headers, config) {
if ((_.select($scope.$parent.$$childHead.holidays, { BeginHour: data.BeginHour }).length == 0) && (_.select($scope.$parent.$$childHead.holidays, { EndHour: data.EndHour }).length == 0) && (_.select($scope.$parent.$$childHead.holidays, { HolidayDate: data.HolidayDate }).length == 0) && (_.select($scope.$parent.$$childHead.holidays, { EndHour: data.EndHour }).length == 0) && (_.select($scope.$parent.$$childHead.holidays, { HolidayName: data.HolidayName }).length == 0))
$scope.$parent.$$childHead.holidays.push(data);
centerList[indexOfCurrentCenter].ticked = false;
alert("holiday was created");
})
.error(function (data, status, headers, config) {
if (status == 409)
alert("Holiday " + data.HolidayName + " Cannot be created for " + data.DN + " BECAUSE OF OVERLAPPED HOLIDAYS.")
})
}
}
})
HTML:
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-click="close(false)" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<form>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div isteven-multi-select
input-model="$parent.$$childHead.centers"
output-model="outputCenters"
button-label="Name"
item-label="Name (Route)"
tick-property="ticked"
max-labels="5" max-height="150px">
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="form-group">
<div class="input-group date">
<input ng-model="HolidayName" type="text" placeholder="Holiday Name" class="form-control">
<span class="input-group-addon">
<span class="glyphicon glyphicon-pencil"></span>
</span>
</div>
</div>
</div>
</div>
<div ng-controller="DatepickerCtrl">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="$parent.dt" is-open="opened" min-date="minDate" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
</div>
<div class="row">
<div class='col-md-8 col-md-offset-2'>
<timepicker-pop input-time="starttime" class="input-group"
show-meridian='showMeridian'>
</timepicker-pop>
</div>
</div>
<div class="row">
<div class='col-md-8 col-md-offset-2'>
<timepicker-pop input-time="endtime" class="input-group"
show-meridian='showMeridian'>
</timepicker-pop>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" ng-click="close(false)" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" ng-click="addHoliday()" class="btn btn-primary" data-dismiss="modal" ng-disabled="conditionsForSendNewHoliday()">Send</button>
</div>
</div>
</div>
Should I add the other controller and the html?

how to establish a two-way binding between a text input and a parent scope model

In my Angular app, I have a view, which is presented as a tabbed UI, with multiple tabs created by default.
Each tab contains a number of Form elements, one of which is a text input named "tabName".
The purpose of each tab is to allow the user to upload an Excel file, and be able to describe the file contents using a few Form fields located on the same page.
All of the form elements in each tab are bound to a controller named "FileUploadController", but, the tab itself (specifically its name) is bound to a different controller, named "TabController".
I need to be able to have a two-way binding between the "tabName" text input in each tab, and the name property of the actual tab (which initially comes from "$scope.workspaces" within the TabController.
Currently, I am trying to handle this by creating a "activeWorkspaceSheetName" function within the TabController, and then referencing it as ng-model for the text input, but, it is not working.
Here are my files:
tabControl.html (the view):
<div class="container form-group">
<br>
<tabset>
<tab ng-repeat="workspace in workspaces"
heading="{{workspace.name}}"
active=workspace.active>
<div ng-controller="FileUploadController">
<hr>
<!--FILE UPLOAD CONTROL-->
<div class="container">
<div class="row">
<div class="col-md-3">
<input type="file" nv-file-select="" uploader="uploader" />
</div>
<div class="col-md-9" style="margin-bottom: 40px">
<h3>Upload queue</h3>
<p>Queue length: {{ uploader.queue.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Name</th>
<th ng-show="uploader.isHTML5">Size</th>
<th ng-show="uploader.isHTML5">Progress</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in uploader.queue">
<td><strong>{{ item.file.name }}</strong></td>
<td ng-show="uploader.isHTML5" nowrap>{{ item.file.size/1024/1024|number:2 }} MB</td>
<td ng-show="uploader.isHTML5">
<div class="progress" style="margin-bottom: 0;">
<div class="progress-bar" role="progressbar" ng-style="{ 'width': item.progress + '%' }"></div>
</div>
</td>
<td class="text-center">
<span ng-show="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
<span ng-show="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
<span ng-show="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
</td>
<td nowrap>
<button type="button" class="btn btn-success btn-xs" ng-click="item.upload()" ng-disabled="item.isReady || item.isUploading || item.isSuccess">
<span class="glyphicon glyphicon-upload"></span> Upload
</button>
<button type="button" class="btn btn-warning btn-xs" ng-click="item.cancel()" ng-disabled="!item.isUploading">
<span class="glyphicon glyphicon-ban-circle"></span> Cancel
</button>
<button type="button" class="btn btn-danger btn-xs" ng-click="item.remove()">
<span class="glyphicon glyphicon-trash"></span> Remove
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!--END OF FILE UPLOAD CONTROL-->
<div class="form-group">
<fieldset>
<legend><strong>Dataset Description</strong> </legend>
<div class="col-sm-6">
<label for="category">Category name</label>
<div id="category">
<isteven-multi-select
input-model="inputCategories"
output-model="outputCategories"
button-label="icon name"
item-label="icon name maker"
tick-property="ticked"
selection-mode="single"
>
</isteven-multi-select>
</div>
<label for="documentAuthor">Document author</label>
<input id="documentAuthor" name="documentAuthor" type="text" class="form-control" ng-model="documentAuthor"/>
<label for="dateDocumentRecieved">Date document recieved</label>
<input id="dateDocumentRecieved" name="dateDocumentRecieved" type="text" class="form-control" ng-model="dateDocumentReceived"/>
<label for="documentReviewer">Document reviewer</label>
<input id="documentReviewer" name="documentReviewer" type="text" class="form-control" ng-model="documentReviewer"/>
</div>
<div class="col-sm-6">
<label for="originalDocumentName">Original document name</label>
<input id="originalDocumentName" name="originalDocumentName" type="text" class="form-control" ng-model="originalDocumentName"/>
<label for="tabName">Sheet Name</label>
<input id="tabName" name="tabName" type="text" class="form-control" ng-model="$scope.$parent.activeWorkspaceSheetName"/>
<label for="dateDocumentProduced">Date document produced</label>
<input id="dateDocumentProduced" name="dateDocumentProduced" type="text" class="form-control" ng-model="dateDocumentProduced"/>
<label for="documentSubmitter">Document submitter</label>
<input id="documentSubmitter" name="documentSubmitter" type="text" class="form-control" ng-model="documentSubmitter"/>
</div>
</fieldset>
</div>
</div>
</tab>
<tab select="addWorkspace()">
<tab-heading> Add Sheet
<i class="icon-plus-sign"></i>
</tab-heading>
</tab>
<tab select="removeWorkspace()">
<tab-heading> Remove Selected Sheet
<i class="icon-plus-sign"></i>
</tab-heading>
</tab>
</tabset>
<br/>
<!--<button type="button" class="btn-primary" ng-click="collectValuesFromEachTab()">Submit Dataset</button>-->
<!--<h3>Workspaces</h3>-->
<!--<pre>{{workspaces|json}}</pre>-->
</div>
tabController.js:
angular.module('TabCtrl', ['ui.bootstrap'])
.controller("TabController", ['$scope','$http', function ($scope, $http) {
console.log("This is TabController");
var setAllInactive = function() {
angular.forEach($scope.workspaces, function(workspace) {
workspace.active = false;
});
};
$scope.activeWorkspaceSheetName = function(){
$scope.workspaces.forEach(function(workspace) {
if(workspace.active){
return workspace.name;
}
});
};
var addNewWorkspace = function() {
var id = $scope.workspaces.length + 1;
$scope.workspaces.push({
id: id,
name: "Sheet " + id,
active: true
});
};
$scope.workspaces =
[
{ id: 1, name: "Sheet 1" ,active:true },
{ id: 2, name: "Sheet 2" ,active:false }
];
$scope.addWorkspace = function () {
setAllInactive();
addNewWorkspace();
};
$scope.removeWorkspace = function() {
angular.forEach($scope.workspaces, function(workspace) {
if(workspace.active){
var index = $scope.workspaces.indexOf(workspace);
console.log('Active Workspace id: ' + index);
$scope.workspaces.splice(index,1);
}
})
};
}]);
fileUploadController.js:
angular.module('FileUploadCtrl', [])
.controller('FileUploadController', ['$scope', 'FileUploader', function($scope, FileUploader) {
console.log('This is File Upload Controller');
$scope.inputCategories = [
{
name: "Category 1"
},
{
name: "Category 2"
},
{
name: "Category 3"
}
];
var selectedCategory;
var uploader = $scope.uploader = new FileUploader({
url: 'http://10.211.55.25:8080/api/files',
tabName: 'sheet1'
});
// FILTERS
uploader.filters.push({
name: 'customFilter',
fn: function(item /*{File|FileLikeObject}*/, options) {
return this.queue.length < 10;
}
});
// CALLBACKS
uploader.onWhenAddingFileFailed = function(item /*{File|FileLikeObject}*/, filter, options) {
console.info('onWhenAddingFileFailed', item, filter, options);
};
uploader.onAfterAddingFile = function(fileItem) {
console.info('onAfterAddingFile', fileItem);
};
uploader.onAfterAddingAll = function(addedFileItems) {
console.info('onAfterAddingAll', addedFileItems);
};
uploader.onBeforeUploadItem = function(item) {
angular.forEach( $scope.outputCategories, function( value, key ) {
selectedCategory = value.name;
item.formData.push({subjectCategory: selectedCategory});
});
$scope.tabName = $scope.$parent.activeWorkspaceSheetName;
item.formData.push({tabName: $scope.tabName,
originalDocumentName: $scope.originalDocumentName,
subject: $scope.subject,
documentAuthor: $scope.documentAuthor,
dateDocumentProduced: $scope.dateDocumentProduced,
dateDocumentReceived: $scope.dateDocumentReceived,
documentSubmitter: $scope.documentSubmitter,
documentReviewer: $scope.documentReviewer,
dataFields: $scope.dataFields});
console.info('onBeforeUploadItem', item);
};
uploader.onProgressItem = function(fileItem, progress) {
console.info('onProgressItem', fileItem, progress);
};
uploader.onProgressAll = function(progress) {
console.info('onProgressAll', progress);
};
uploader.onSuccessItem = function(fileItem, response, status, headers) {
console.info('onSuccessItem', fileItem, response, status, headers);
};
uploader.onErrorItem = function(fileItem, response, status, headers) {
console.info('onErrorItem', fileItem, response, status, headers);
};
uploader.onCancelItem = function(fileItem, response, status, headers) {
console.info('onCancelItem', fileItem, response, status, headers);
};
uploader.onCompleteItem = function(fileItem, response, status, headers) {
console.info('onCompleteItem', fileItem, response, status, headers);
};
uploader.onCompleteAll = function() {
console.info('onCompleteAll');
};
console.info('uploader', uploader);
}]);
What is the proper way to have this two-way binding, so, when the user updates the tabName text input in each tab, the actual tab's name is also updated?
If I understood correctly you has an input tabName for each tab so you can try put this model in the tabName input:
<input id="tabName" name="tabName" type="text" class="form-control" ng-model="workspace.name"/>
Remember every time that angular can't find a property in a scope they look if exist in his parent, and if not exist they check in his parent parent and so on...

Resources