Angularjs transform array from input checkbox - javascript

I have multiple input checkboxs created from a model with angular using ng-repeat, when I select some of them I get this:
var accounts = [AA764: true, AA324: true, AA234: false, AA553: true, AA7365: false];
But I need following structure to manipulate in controller that calls and REST API:
var accounts = ['AA764', 'AA324', 'AA553'];
This is the way I obtain the array to be converted:
<span><i class="pe-7s-trash"></i> Eliminar</span>
<tbody ng-repeat="account in reconcileBankAccounts">
<tr>
<td><input type="checkbox" ng-model="asobancariaAccounts[account.accountBankId]"> {{account.accountName}}</td>
<td>{{account.paymentMethodMain}}</td>
<td><i class="pe-7s-pen"></i> Editar</td>
</tr>
</tbody>
In the Controller:
$scope.deleteAsobancariaAccountModalDialog = function (asobancariaAccounts) {
console.log(asobancariaAccounts); // [AA764: true, AA324: true, 'AA234': false, 'AA553': true, 'AA7365': false]
var modalInstance = $modal.open({
templateUrl: SECURE_CONSTANTS.VIEWS + SECURE_CONSTANTS.MODALS.DELETE_ASOBANCARIA_ACCOUNTS,
size: 'md',
keyboard: true,
controller: 'asobancariaCreateController',
scope: $scope,
resolve: {
asobancariaAccount: function(){
asobancariaAccounts.action = "delete";
return asobancariaAccounts;
}
}
});
};
Just those checkbox that are selected, I have tried with the javascript foreach function but I cannot make it work. Is there any library for angular or maybe with bower that can help me? Thanks.

You can try using ng-true-value.
Read more information in: https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D

Related

ng-repeat not populating table

I've populated a table with data from a JSON file, and then when the user clicks on an item in the table, a container and it's fields display below and it SHOULD be populated with that specific data, though it isn't.
The function select is invoked through list-patents.htm which contains the table with a list of patents. I have used the $rootScope object so the function is accessible from multiple controllers i.e. patentDetailsCtrl
Why isn't my table in patent-item.htm being populated with the ng-repeat directive?
var app = angular.module('myApp', ['ngRoute', 'angularMoment', 'ui.router', "chart.js"]);
$stateProvider
.state("patents.list.item", {
url: "/patent-item",
templateUrl: "templates/patents/list/patent-item.htm",
params: {
id: null,
appNo: null,
clientRef: null,
costToRenew: null,
renewalDueDate: null,
basketStatus: null,
costBandEnd: null,
nextStage: null
},
controller: "patentDetailsCtrl"
})
app.run(function($rootScope) {
$rootScope.select = function() {
return $rootScope.patentItem = item;
}
});
app.controller('patentDetailsCtrl', ['$scope', '$http', function($scope, $http) {
$scope.selectedPatent = $scope.patentItem;
console.log($scope.selectedPatent);
}]);
list-patents.htm
<tbody>
<tr ng-repeat="x in patents">
<td ng-click="select(x)"><a ui-sref="patents.list.item({id: x.id, appNo: x.applicationNumber, clientRef: x.clientRef, costToRenew: x.costToRenew, renewalDueDate: x.renewalDueDate, basketStatus: x.basketStatus, costBandEnd: x.costBandEnd, nextStage: x.nextStage})">{{x.applicationNumber}}</a></td>
<td ng-bind="x.clientRef"></td>
<td ng-bind="x.costToRenew">$</td>
<td ng-bind="x.renewalDueDate"></td>
<td><button type="button" class="btn btn-danger" ng-click="remove(x.id)">Remove</button></td>
</tr>
</tbody>
patent-item.htm
<table>
<tbody>
<thead>
<tr>
<td>applicationNumber</td>
<td>clientRef</td>
<td>costToRenew</td>
<td>renewalDueDate</td>
<td>basketStatus</td>
<td>costBandEnd</td>
<td>nextStage</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in selectedPatent">
<td>{{x.applicationNumber}}</td>
<td>{{x.clientRef}}</td>
<td>{{x.costToRenew}}</td>
<td>{{x.renewalDueDate}}</td>
<td>{{x.basketStatus}}</td>
<td>{{x.costBandEnd}}</td>
<td>{{x.nextStage}}</td>
</tr>
</tbody>
</table>
</tbody>
You need to correct below points:
your $rootScope.select() method doesn't accept data (select(x)) passed from your list-patents.htm, So put item as param.,
Like : $rootScope.select = function(item) { \\ code
Sine you do ng-repeat on $rootScope.patentItem, then I guess you need to make it array, and push the passed data to it. (No need of return statement as well.)
So run block should be like :
app.run(function($rootScope) {
rootScope.patentItem = [];
$rootScope.select = function(item) {
$rootScope.patentItem.push(item);
}
});
See this Example Fiddle
To me it seems like you're trying to access the patentItem selected in your select function. If you're passing it to the $rootScope this way, you will also need to access it this way.
So change the line as follows...
$scope.selectedPatent = $rootScope.patentItem

Angular Modal Text Boxes Not Getting Populated with ngModel

I have a table with TV show data on it. I populate the table with dir-paginate/ng-repeat and I can click a row to open a modal to be able to edit the show but the ng-model data is not loading on the text boxes within that modal.
<tr id='schedule_row' class='hover_click_cell' dir-paginate='tv_show in tv_shows | orderBy:sortType:sortReverse | itemsPerPage:10'>
<td class='center_text clickable_cell cell_width' ng-click='alter_show(tv_show)'>{{tv_show.show_name}}</td>
When clicked, it calls the function alter_show()
$scope.alter_show = function(show)
{
$scope.edit_show = show;
var modalInstance = $uibModal.open ({ animation: $controller.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'edit_tv_show.html',
controller: 'EditTvShowCtrl',
controllerAs: '$controller',
size: 'sm',
backdrop: 'static',
keyboard: false
});
modalInstance.result.then(function (action)
{
},
function () {
});
}
The data passed looks like this in JSON form:
{"watched":false,"id":1,"show_name":"The Walking Dead","season":1,"episode":1,"season_episode":"Season 1, Episode 1","$$hashKey":"object:4"}
I pass in the show details and set it to the $scope.edit_show object. The data being passed on is not empty but when the modal is opened, the text boxes aren't populated. These are the input boxes:
$scope.edit_show = {
show_name: '',
season: 0,
episode: 0,
watched: 0
};
<div class='form-group'>
<label for='show_name'>Show Name:</label>
<input type='text' class='form-control' id='edit_show_name' ng-model='edit_show.show_name'>
</div>
<div class='form-group'>
<label for='season'>Season:</label>
<input type='number' class='form-control' id='edit_season' ng-model='edit_show.season'>
</div>
How can I get this to populate the text box with the details from the row that has been clicked?
I've manage to figure it out using resolve for the modalInstance.
$scope.alter_show = function(show)
{
var modalInstance = $uibModal.open ({ animation: $controller.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'edit_tv_show.html',
controller: 'EditTvShowCtrl',
controllerAs: '$controller',
size: 'sm',
backdrop: 'static',
keyboard: false,
resolve: { tv_show : function() { return show; } }
});
modalInstance.result.then(function (action)
{
},
function () {
});
}
angular.module('ui.bootstrap').controller('EditTvShowCtrl', function ($uibModalInstance, $scope, tv_show)
{
var $controller = this;
$scope.edit = tv_show;
});

AngularJS: Compiling the output of a directive

i have some kind of legacy angularjs code which creates a dynamic table using a directive where the controller can overwrite the behavior of the table (on how to display the data)
It consists of the following setup (simplified):
Directive's controller
.directive('datatable', [function () {
return {
scope: {
items: '=',
tablemetadata: '=',
processors: '=?'
},
controller: ...
$scope.processField = function processField(item, data){
if($scope.processors === undefined){return;}
for(var i = 0; i < $scope.processors.length; i++){
if($scope.processors[i].field===field){
var newData = $scope.processors[i].processor(item, data);
return $sce.trustAsHtml(newData);
}
}
return data;
};
...
Directive's Template
<tr ng-repeat="item in items">
<td ng-repeat="column in tableMetadata.columns" ng-bind-html="processField(column.field, $eval('item.'+column.field))"></td>
</tr>
Controller
$scope.myItems = [{id: 2, otherProperty: "text"}];
$scope.tableMetadata = {
columns: [
{field: 'id', headerKey: 'object id'},
{field: 'otherProperty', headerKey: 'some data'},
]
};
$scope.tableProcessors = [
{field: 'id', processor: function(entry, data){ //data = content of object.id
var retVal = "<a ng-click='alert(" + data + ");'>click me</a>";
return retVal;
}}
];
Controller's view
<datatable items="myItems" tablemetadata="tableMetadata" processors="tableProcessors"></datatable>
I need to generate buttons (or other html-elements) for some specific properties, like a link (like shown above).
The Button is displayed but the ng-click handler is not working. This makes sense since it wasn't compiled to the scope.
How do I correctly compile the new element and add it to the table?
In your link method in the directive you have to use
elem.append( $compile(html)(scope) );
As for separating the concerns cleanly, I would make each <td> its own directive that inherits what you are currently concatenating as a string in its isolated scope properties. Instead of
var retVal = "<a ng-click='alert(" + data + ");'>click me</a>";
<tr ng-repeat="item in items">
<td ng-repeat="column in tableMetadata.columns" ng-bind-html="processField(column.field, $eval('item.'+column.field))"></td>
</tr>
use something like:
<tr ng-repeat="item in items">
<table-item ng-repeat="..." process-field="item"></table-item>
</tr>
/** directive compiles dynamically */
scope: {
processField: '='
},
link: function(scope, elem, attr, ctrl) {
var template = `<a ng-click="${ctrl.processField}"></a>`;
elem.append( $compile(template)(scope) );
}
A simple solution can be to not use an isolated scope.
Change your scope from scope: { ... } to scope: true and use $scope.$eval to evaluate your attributes.
Another solution (most elegant) can be to use angularjs transclusion (see here). But this solution ask to modify your dom representation of your directive.

Change elements in a directive template based on scope data

I have a directive nested within an ng-repeat. The ng-repeat item is passed to the directive. I am attempting to generate a directive template (for testing) or templateUrl with variable elements based on a key/value in the item passed to the directive. Essentially, if item.number > 50 make the button red else make it blue.
I may be using the wrong tool to solve the problem. The goal is to use something like this to change Bootstrap tags. For instance the logic:
if item.number > 50:
class="btn btn-danger"
else:
class="btn btn-success"
If possible I'm trying to solve this with using templateUrl: as I'd like the button to launch a bootstrap modal and that's a lot to fit into the basic template option. It's much cleaner to pass the template individual scope variables.
Here is a JSFiddle that tries to describe the problem.
html
<div ng-controller="TableCtrl">
<table>
<thead>
<tr>
<th>#</th>
<th>Button</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in buttons">
<td>{{item.id}}</td>
<td new-button item='item'></td>
</tr>
</tbody>
</table>
</div>
app.js
var myApp = angular.module('myApp', []);
function TableCtrl($scope) {
$scope.buttons = {
button1: {
id: 1,
number: '10',
},
button2: {
id: 2,
munber: '85',
}
};
};
myApp.directive('newButton', function() {
return {
restrict: 'A',
replace: true,
scope: {
item: '=',
},
link: function(elem, attrs, scope) {
// This is most likely not the right location for this
/*if (item.number > 50) {
button.color = red
}, else {
button.color = blue
}; */
},
template: '<td><button type="button">{{button.color}}</button></td>'
}
});
Perhaps you can use an ng-class for this:
<button ng-class="{
'btn-danger': item.number > 50,
'btn-success': item.number <= 50
}"></button>
See https://docs.angularjs.org/api/ng/directive/ngClass
If you really need a custom directive you could try using it like this
link: function(scope,elem,attrs) {
var item=scope.item;
if (item.number > 50) {
elem.addClass("btn-danger");
} else {
elem.addClass("btn-success");
}
}
But I think that for what you're trying to achieve it's better to use the ngClass directive as follows:
<button type="button" item="item" class="btn" ng-class="item.number > 50?'btn-danger':'btn-success'"></button>
Looking at your example code, there are a few points to note:
Typo in button 2's 'munber' property.
The link function doesn't use dependency injection, so the order of the arguments does matter. Scope needs to be moved first.
Your commented out bit of code is close to working, but you need to address the variables as properties of scope - item is on scope, and the button object you are creating needs to be created on scope in order to be addressed as 'button.' from your view template.
This works (it would be better, as others have said, to use ng-class, rather than class plus moustache syntax, but I wanted to stay as close to your code sample as possible):
HTML
<div ng-controller="TableCtrl">
<table>
<thead>
<tr>
<th>#</th>
<th>Button</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in buttons">
<td>{{item.id}}</td>
<td new-button item='item'></td>
</tr>
</tbody>
</table>
</div>
JS
var myApp = angular.module('myApp', []);
function TableCtrl($scope) {
$scope.buttons = {
button1: {
id: 1,
number: '10',
},
button2: {
id: 2,
number: '85',
}
};
};
myApp.directive('newButton', function() {
return {
restrict: 'A',
replace: true,
scope: {
item: '=',
},
link: function(scope, elem, attrs) {
scope.button = {};
if (scope.item.number > 50) {
scope.button.class = 'btn btn-danger';
} else {
scope.button.class = 'btn btn-success';
};
},
template: '<td><button type="button" class="{{button.class}}">Press Me?</button></td>'
}
});
CSS
.btn-danger {
background-color: red;
}
.btn-success {
background-color: green;
}
Modified JSFiddle

AngularJS : directive does not update scope after $http response in parent scope

I got this directive:
.directive('studentTable', [function() {
return {
restrict: 'A',
replace: true,
scope: {
students: "=",
collapsedTableRows: "="
},
templateUrl: 'partials/studentTable.html',
link: function(scope, elem, attrs) {
...
}
}
}
Template:
<table class="table">
<thead>
<tr>
<th><b>Name</b></th>
<th><b>Surname</b></th>
<th><b>Group</b></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="student in students track by $index">
<td>{{ student.name }}</td>
<td>{{ student.surname }}</td>
<td>{{ student.group }}</td>
</tr>
</tbody>
</table>
Use directive in my html like this:
<div student-table students="students"
collapsedTableRows="collapsedTableRows"></div>
And the parent controller:
.controller('SchoolController', ['$scope', 'User', function($scope, User){
$scope.students = [];
$scope.collapsedTableRows = [];
$scope.search = function(value) {
if(value) {
var orgId = $state.params.id;
var search = User.searchByOrg(orgId, value);
search.success(function (data) {
$scope.students = data;
$scope.collapsedTableRows = [];
_(data).forEach(function () {
$scope.collapsedTableRows.push(true);
});
});
}
}
}])
Now at the beginnig, the table is empty, because no users in students array. After I click search, and get list of students object, I put them to scope variable, but the directive does not update, neither it find change in model (scope.$watch('students',...). What am I missing?
P.S. If I simulate the data using $httpBackend, directive works as it should.
Please make sure that data object returning array of student because somtimes you have to use data.data that simple demo should helps you:
http://plnkr.co/edit/UMHfzD4oSCv27PnD6Y6v?p=preview
$http.get('studen.json').then(function(students) {
$scope.students = students.data; //<-students.data here
},
function(msg) {
console.log(msg)
})
You should try changing the controller this way
...
$scope.$apply(function() {
$scope.students = data;
})
...
This will start a digest loop, if it's not already in progress.
Another form that will do almost the same thing is this:
...
$scope.students = data;
$scope.$digest()
...
PS:
The first method is just a wrapper that execute a $rootScope.$digest() after evaluating the function, considering that a $digest evaluates the current scope and all it's children calling it on the $rootScope is pretty heavy.
So the second method should be preferred if it works.

Categories