Pass parameters to Angular's ng-include - angularjs

I need two tables on my page and a lot of elements inside tables.
I created file AccountItem.html:
<div data-as-sortable-item-handle>
<table>
<tr>
<td class="draggable-index-field">
{{$index + 1}}
</td>
<td class="draggable-name-field">
{{item.accountName}}
</td>
<td class="draggable-enabled-field">
<input id="enabled-{{$index}}" type="checkbox" name="accounts[]" ng-checked="item.enabled" disabled/>
</td>
</tr>
</table>
This file is related to each row in table.
Also I created file for table SortAccountList.html:
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title ng-binding">{{title}}</h3>
</div>
<div class="panel-body">
<table>
<td class="draggable-index-field">
#
</td>
<td class="draggable-name-field">
Account Name
</td>
<td class="draggable-enabled-field">
Enabled
</td>
</table>
<ul data-as-sortable = "sortableOptions" data-ng-model="accountList" class="draggable-area">
<li ng-repeat="item in accountList" data-as-sortable-item ng-include="'AccountItem.html'"></li>
</ul>
</div>
I include this file with directive in my main file:
<div ng-include="'SortAccountList.html'" onload="title = 'Sorted Account List'; accountList = sortedAccounts"></div>
When I load this page in browser it shows me table, title on it which I pass with "title" parameter. But it does not want to show rows in the table. However, if I change accountList to sortedAccounts which is a List in my controller it shows all rows.
I can not use sortedAccounts because I have second table where I want to pass different accounts from my controller.
So, my question, how to pass properly this parameter? Thank you!

The ng-init="" attribute on the include tag should do what you need.
<div ng-include="'SortAccountList.html'"
ng-init="title = 'SortedAccount List'; accountList = sortedAccounts"></div>`

Do not use ngInclude. Use a directive and pass data using directive's scope.
directive('sortAccountList', function() {
return {
restrict: 'E',
scope: {
title: '=',
accountList: '='
},
templateUrl: 'SortAccountList.html'
};
});

Related

How to avoid ng-init in angular?

I want to show message when ng-repeat collection is empty i.e.:
<div ng-init="filteredArray=(array|filter:{...})">
<h1 ng-if="!filteredArray.length">Empty array</h1>
<table ng-if="filteredArray.length">
<tr ng-repeat="element in filteredArray">
<td>{{element}}</td>
</tr>
</table>
</div>
The problem is that ng-init will not watch for modification of the source array. Any hint how to do it properly?
You can just create the filtered variable in the ng-repeat, and use that one:
<div>
<h1 ng-if="!filteredArray.length">Empty array</h1>
<table ng-if="filteredArray.length">
<!-- here angular assigns the filtered array to the 'filteredArray' variable,
which then can be used -->
<tr ng-repeat="element in filteredArray=(array|filter:{...})">
<td>{{element}}</td>
</tr>
</table>
</div>
See also this jsfiddle
EDIT
If you don't like the ugly expression, you can also do something like this:
function myController ($scope, $filter) {
$scope.$watch("theFilter", function (val) {
$scope.filteredArray = $filter("filter")($scope.array, val);
});
}
And in your html:
<tr ng-repeat="element in filteredArray">
..
</tr>
Check in this jsfiddle
Check ng-repeats $last to show your message like below
<div ng-repeat="n in data track by $index">
<h1 ng-if="$last">Empty array</h1>
</div>
In your case you can have a variable at the table level and then set it to $last,when it'll be true your message will show like below
<body ng-app="app" ng-controller="ctrl">
<div ng-init='counter=false'>
<h1 ng-if='counter'>Empty array</h1>
<table ng-if="myData.length">
<tbody>
<tr ng-repeat="element in myData track by $index" ng-init="counter=$last">
<td>{{element}}
<ng-if ng-init='sync($last)'/>
</td>
</tr>
</tbody>
</table>
</div>
</body>
Your controller should look like below
var app=angular.module('app',[])
app.controller('ctrl',function($scope){
$scope.myData=['a','b','c']
$scope.sync=function(val)
{
alert(val)
$scope.counter=val
}
})
Since you have stored (array|filter:{...}) value into filteredArray, you cannot modify it in the template.
You should repeat (array|filter:{...}) code in the template.
<h1 ng-if="!(array|filter:{...}).length">Empty array</h1>
<table ng-if="(array|filter:{...}).length">
<tr ng-repeat="element in (array|filter:{...})">
<td>{{element}}</td>
</tr>
</table>

Edit many same name isolated variables at a time in Angularjs

I have a table. Each cell can hold its value as a string or the edit in place template for that datatype.
I render one thing or the other based on the value of the variable "ttt" of that table cell. If ttt=true it renders the editing template if false it renders the value as string.
The way things are set up you can toggle between true and false of a specific cell each time you double-click on it.
I wish to have as well a button at top of the page that toggles all the "ttt" variables between true or false at the same time for all the table cells.
What is the best way to do this the way I have things set up.
Here is the template of the table:
<script type="text/ng-template" id="editabletable">
<div ng-controller="listeditorController" cg-busy="{promise:myPromise, message:' '}">
<div tasty-table bind-resource-callback="getResource" bind-init="init" bind-filters="filterBy">
<div class="table-responsive" style="width:100%;">
<table class="superResponsive" adapt-table style="width:{{theWidth}};margin:0 auto;">
<thead>
<!-- <thead tasty-thead bind-not-sort-by="notSortBy"></thead> -->
<tr>
<th style="max-width:{{columnWidth}}px;" ng-repeat="attobj in rows[0].class_attributes()">
{{ attobj.label }}
</th>
</tr>
<tr>
<td style="max-width:{{columnWidth}}px;" ng-repeat="attobj in header.columns track by $index">
<input ng-if="attobj.filterable" type="text" class="form-control input-sm" ng-model="filterBy[attobj.filterkey || attobj.key]" ng-model-options="{ debounce: 2000 }" />
</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="dbo in rows">
<td style="max-width:{{columnWidth}}px;" ng-repeat="attobj in header.columns" ng-dblclick="ttt=!ttt">
<div>
<form name="theForm" novalidate>
<div ng-if="ttt" ng-init="attobj = attobj.attobj" ng-include src="getAttValuesEditorTemplate(dbo, attobj)">
</div>
</form>
<div ng-if="!ttt" ng-repeat="v in dbo.get4(attobj.key) track by $index">
<p ng-if="v.cid">{{ v.displayName() }}</p>
<p ng-if="!v.cid">{{ v }}</p>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div tasty-pagination bind-list-items-per-page="listItemsPerPage" bind-items-per-page="itemsPerPage" bind-template-url="'/templates/table/pagination.html'"></div>
</div>
</div>
</script>
Ok, the solution I came up with is fairly simple but SLOW.
I added a controller at the table level which defines a scope variable "editGird" defined on load as "false".
On click of the button "Edit gird" the scope variable "editGird" toggles between true and false.
If set to true the cell is rendered like:
<td ng-if="editGird==true" style="max-width:{{columnWidth}}px;" ng-repeat="attobj in header.columns">
<div>
<form name="theForm" novalidate>
<div ng-init="attobj = attobj.attobj" ng-include src="getAttValuesEditorTemplate(dbo, attobj)">
</div>
</form>
</div>
</td>
If editGird == false:
<td ng-if="editGird==false" style="max-width:{{columnWidth}}px;" ng-repeat="attobj in header.columns" ng-dblclick="ttt=!ttt">
<div>
<form name="theForm" novalidate>
<div ng-if="ttt" ng-init="attobj = attobj.attobj" ng-include src="getAttValuesEditorTemplate(dbo, attobj)">
</div>
</form>
<div ng-if="!ttt" ng-repeat="v in dbo.get4(attobj.key) track by $index">
<p ng-if="v.cid">{{ v.displayName() }}</p>
<p ng-if="!v.cid">{{ v }}</p>
</div>
</div>
</td>
Controller:
app.controller('editGirdController', ['$scope',
function ($scope) {
$scope.editGird= false;
$scope.onOff = function() {
if ($scope.editGird == true){
$scope.editGird = false;
$scope.editGirdColor ='#0887A7';
} else{
$scope.editGird = true;
$scope.editGirdColor ='lightGreen';
}
console.log($scope.editGird);
console.log($scope);
}
}
]);
But this is very very slow!!!
On tables which have 25-35 columns it takes 1 second for each 5 rows to render!!!
How can I make this more efficient???

ng-show does not work with custom directive

I've just started using AngularJS and wanted to create a custom template directive for creating "in-place" editable tables. The idea would be to have something like:
<tr ng-repeat="customer in model.customers">
<ng-template ng-hide="customer === model.selectedCustomer"> <!-- display template-->
<td>{{customer.name}}</td>
</ng-template>
<ng-template ng-show="customer === model.selectedCustomer"> <!-- edit template -->
<td><input type="text" ng-model="customer.name"/></td>
</ng-template>
</tr>
It could then also be extended to specify a templateUrl e.g. <ng-template template-url="foo.html"></ng-template>
When I apply the ng-show directive to my custom directive it does not work. Here's the code for my directive:
var demo = angular.module("demo", [])
.directive("ng-template", function() {
return {
restrict: "E",
replace: true,
transclude: true
}
});
and HTML (http://jsfiddle.net/benfosterdev/ASXyy/):
<div ng-app="demo">
<table>
<tr ng-repeat="name in ['jane', 'john', 'frank']">
<ng-template ng-show="name !== 'frank'">
<td>{{name}}</td>
</ng-template>
</tr>
</table>
</div>
Furthermore, when I look at the generated HTML my custom directive doesn't even appear in the table:
<div ng-app="demo" class="ng-scope">
<ng-template ng-show="name !== 'frank'" class="">
</ng-template>
<table>
<tbody>
...
</tbody>
</table>
</div>
Essentially I'm trying to avoid writing code like this (setting the ng-show directive on every <td> element):
<table>
<tr ng-repeat="customer in customers">
<ng-template>
<td ng-hide="isSelected">{{customer.name}}</td>
<td ng-hide="isSelected">{{customer.age}}</td>
<td ng-hide="isSelected"><button ng-click="edit(customer)"</td>
<td ng-show="isSelected"><input type="text" ng-model="customer.name"/></td>
<td ng-show="isSelected"><input type="text" ng-model="customer.age"/></td>
<td ng-show="isSelected"><button ng-click="save(customer)"</td>
</ng-template>
</tr>
</table>
A couple of things occur to me when I look at your code.
ng-include offers very similar functionality to your proposal for extending ng-template. If you're going to load a view based on the state of the underlying model then I think this would be the way to go.
If you're not going to be loading the template from a separate view file, why not just use ng-show (or ng-if / ng-switch, which I prefer in most cases) on your td element?
Here is some example code using ng-include:
<table>
<thead>
<th>One</th>
<th>Two</th>
<th>Three</th>
<th></th>
</thead>
<tbody>
<tr ng-repeat="item in items" ng-include="getTemplate(item)"></tr>
</tbody>
</table>
Here is the full JSFiddle: http://jsfiddle.net/qQR6j/2.
Use ng-repeat-start and ng-repeat-end to specify the two alternative <tr> tags.
<div ng-app="demo">
<table ng-controller="Ctrl">
<tr ng-repeat-start="name in ['jane', 'john', 'frank']" ng-hide="isSelected(name)">
<td>{{name}} <button ng-click="select(name)">edit</button></td>
</tr>
<tr ng-repeat-end ng-show="isSelected(name)">
<td>{{name}}!</td>
</tr>
</table>
</div>
With this javascript
var demo = angular.module("demo", []);
demo.controller("Ctrl",
function Ctrl($scope) {
var selected;
$scope.isSelected = function(name) {
return selected === name;
};
$scope.select = function(name) {
selected = name;
};
});
Live example: http://jsfiddle.net/6FtjG/1/
Your browser renders the 'ng-template' outside of the table because its not a valid child of tr. Even if you have set replace to true, the directive needs to be rendered before it can be replaced.
You can see it is because of the table, because this does work:
<div>
<div ng-repeat="name in ['jane', 'john', 'frank']">
<ng-template ng-show="name !== 'frank'">
<div >{{name}}</div>
</ng-template>
</div>
</div>
see: Fiddle
This is something your browser does so you cannot avoid it.

Angularjs : update variable using {{key}} inside ng-repeat

I set up an example to demonstrate my problem :
Here is the associated fiddle link : http://jsfiddle.net/kqw6N/
<div ng-app>
<span ng-init="myvar = {myattribute:'init'}">{{myvar.myattribute}}</span>
<table ng-init="myarray = {'key1': 'value1', 'key2': 'value2'}"><tbody>
<tr>
<td ng-repeat="(key, value) in myarray" ng-click="myvar.myattribute='{{key}}'">
{{value}}
<span ng-click="myvar.myattribute='ok'">test</span>
</td>
</tr>
</tbody></table>
</div>
I would like to update myvar.myattribute while I click on the td inside ng-repeat. It works if I use a constant, but not if I use {{key}}.
You don't need to embrace your key variable. You can access it as follows:
<td ng-repeat="(key, value) in myarray" ng-click="myvar.myattribute=key">
It's already in scope, so it will be found by angular.

Why would ng-repeat fail to loop with $http.get JSON but work when it's hard coded?

I have an Angular project using ng-repeat that has been working fine with a temp JSON string coded into the controller:
function DocsController($scope, $http){
$scope.applicationData = [
{"Item":"1", Value: "Red"}, {"Item":"2", Value: "Orange}
];
}
But for some reason, when I move that JSON into a file, and pull it in via $http.GET, the ng-repeat stops working. No loops, nothing- even though I can get applicationData.length and other properties off the object outside the loop:
$http.get('jsonData/docs.json').success(function(data) {
alert (data);
$scope.applicationData = data;
});
In the above example, the alert shows the JSON string, so I know it's getting loaded properly. I can call {{applicationData.length}} and it will render 2. So I know the data is there, it's just the ng-repeat stops looping when the data is acquired via $http.get.
Any ideas? Many thanks!
Item template (Note that the line {{applicationData.length}} renders properly- so I know the data is there).
<div class="row-fluid">
<div class="box span12" ng-controller="DocsController">
<div class="box-header">
<h2><i class="halflings-icon list-alt"></i><span class="break"></span><strong>Application Documents</strong></h2>
<div class="box-icon">
<span><input type="checkbox" id="completedApplicationCheckbox" ng-model="trueApplication" value="option1" checked>Show Completed </span>
<i class="halflings-icon chevron-up"></i>
</div>
</div>
</br>
<table class="table table-striped table-bordered bootstrap-datatable datatable">
<thead>
<tr>
<th>Document Title <i class="halflings-icon chevron-down"></i></th>
<th>Date <i class="halflings-icon chevron-down"></i></th>
<th>Owner <i class="halflings-icon chevron-down"></i></th>
<th>Status <i class="halflings-icon chevron-down"></i></th>
<th>Actions <i class="halflings-icon chevron-down"></i></th>
</tr>
</thead>
<tbody>
<h2>{{applicationData.length}}</h2>
<tr ng-repeat="item in applicationData" class="application-{{item.status}}">
<td><i class="halflings-icon file"></i> {{item.name}}</td>
<td class="center">{{item.lastModified | date:'short'}}</td>
<td><i class="halflings-icon {{getIconType(item.owner)}}"></i> {{item.owner}}</td>
<td class="center" ng-bind-html-unsafe="createStatus(item.status)">
</td>
<td class="center" ng-bind-html-unsafe="createActionButton(item.status)">
</td>
</tr>
</tbody>
</table>
</div>
</div>
-Edit-
try using .then()
$http.get('jsonData/docs.json').then(function(data){
$scope.applicationData = data
});
Try this:
$scope.applicationData = [];
$http.get('jsonData/docs.json').success(function(data) {
$scope.applicationData.push(data);
});
I realized there was a conflict with the datatable jquery plug-in (http://www.datatables.net/). I'm afraid it won't work with Angular, because it's an excellent piece of software, but I'm having to disable it for now.

Resources