$compile does not compile directive template with ngRepeat - angularjs

After hour of powergoogle I can not imagine why directive`s template does not compile.
So this is my partial view html: (see the ngRepeat)
<appheader currenttab="currentTab"></appheader>
<div class="l-c-r-panes">
<div class="l-pane">
<renters></renters>
</div>
<div class="c-pane">
<div class="form-header" style="position: relative;">
<input class="form-control filter-above-table" type="text" ng-model="filter.$" custom-search />
<table ng-table="invoiceGrid" class="table" id="invoice-table">
<tr ng-repeat="invoice in $data"
ng-click="invoiceGridRowClick(invoice, $data)"
ng-class="{'active': invoice.$selected}" invoice-info-tooltip="invoice">
<td class="invoice-num-column" data-title="'Счет'" sortable="'Invoice'" >{{invoice.Invoice}}</td>
<td data-title="'Арендатор'" sortable="'Renter'">{{invoice.Renter}}</td>
<td class="invoice-sum-column" data-title="'Сумма по счёту'" sortable="'InvoiceSum'">{{invoice.InvoiceSum}}</td>
<td class="invoice-sum-column" data-title="'Оплата (сумма)'" sortable="'PaySum'">{{invoice.PaySum}}</td>
</tr>
</table>
</div>
</div>
<div class="r-pane">
<tasks></tasks>
</div>
</div>
<script type="text/ng-template" id="invoiceTooltipTemplate">
<div ng-repeat="employee in employees">
<div>{{employee.Post}}</div>
<div>{{employee.Name}}</div>
<div>{{employee.Phone}}</div>
<div>{{employee.Info}}</div>
<div>
</script>
And that is my invoiceInfoTooltipDirective:
//require qtip2
angular.module('invoiceModule')
.directive('invoiceInfoTooltip', ['$compile', function ($compile) {
return {
restrict: 'A',
scope: {
invoice: '=invoiceInfoTooltip'
},
link: function (scope, el, attrs) {
if (scope.invoice) {
var tooltipTitle = scope.invoice.Renter;
var tooltipText = '';
scope.employees = scope.invoice.RenterInfo.Employees;
tooltipText = $compile($('#invoiceTooltipTemplate').html())(scope);
el.qtip({
overwrite: true,
content: {
title: tooltipTitle,
text: tooltipText
},
style: {
classes: 'qtip-light invoice-qtip c-invoice-table-tooltip'
},
show: {
event: 'click',
solo: true
},
hide: {
fixed: true,
leave: true,
event: null
},
position: {
my: 'top center',
target: 'mouse',
adjust: {
mouse: false
}
}
});
}
}
};
}]);
directive use template #invoiceTooltipTemplate located in partial view
If this template do not have ngRepate, $compile in directive works fine. But I need iterate some content in template and want to use ngRepeat.
No console errors. Nothing.
If temlate does not compile it return this jquery obj:
[comment, jquery: "2.1.1", constructor: function, selector: "", toArray: function, get: function…]
0: comment
baseURI: null
childNodes: NodeList[0]
data: " ngRepeat: employee in employees "
firstChild: null
jQuery21106483948081731796: undefined
lastChild: null
length: 33
localName: null
namespaceURI: null
nextElementSibling: div.ng-scope
nextSibling: div.ng-scope
nodeName: "#comment"
nodeType: 8
nodeValue: " ngRepeat: employee in employees "
ownerDocument: document
parentElement: null
parentNode: document-fragment
previousElementSibling: null
previousSibling: null
textContent: " ngRepeat: employee in employees "
__proto__: Comment
length: 1
__proto__: Object[0]
I had similar situation in my project, but there`re no ngTable directive with ngRepeat. And it works fine.

Template always must have root element. So easy mistake and I got it..
So template looks like this. And it works.
<script type="text/ng-template" id="invoiceTooltipTemplate">
<div>
<div ng-repeat="employee in employees">
<div>{{employee.Post}}</div>
<div>{{employee.Name}}</div>
<div>{{employee.Phone}}</div>
<div>{{employee.Info}}</div>
</div>
</div>
</script>

Related

AngularJS show/hide with a function() call

Is it possible to show/hide an element after a function call that returns a boolean? Scenario is, to show "Ready" when all n-items have an "agreed" flag. If not, show something else. Value of agreed flag is changed with a radio button.
$scope.data = [
{
title: "Agreement #1",
agreed: false,
},
{
title: "Agreement #2",
agreed: false,
},
];
$scope.ready = function()
{
var go = true;
angular.forEach($scope.data, function(item, key) {
go &= item.agreed==true;
});
return go;
}
Then, calling:
<div ng-show="ready()">Go!</div>
<div ng-hide="ready()">Missing the points.</div>
Problem with this code: If all radio buttons are checked, ie. all values of agreed flag are set to true, the ready() is not auto updated.
You can bind the boolean value of agreed to the ng-model of the radio button and use ng-value for setting true/false for each agreement.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.data = [
{
title: "Agreement #1",
agreed: false,
},
{
title: "Agreement #2",
agreed: false,
}
]
$scope.ready = function()
{
var go = true;
angular.forEach($scope.data, function(item, key) {
go &= item.agreed==true;
});
return go;
}
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-show="ready()">Go!</div>
<div ng-show="!ready()">Missing the points.</div>
<table>
<tr>
<th>Agreement </th>
<th>Status</th>
</tr>
<tr ng-repeat="value in data">
<td>{{value.title}}</td>
<td>
Yes <input type="radio" ng-model="value.agreed" ng-value="true" />
No <input type="radio" ng-model="value.agreed" ng-value="false" />
</td>
</tr>
</table>
<span>{{data}}</span>
</div>
</body>
</html>
i think u missed the data variable square bracket
$scope.data = [
{
title: "Agreement #1",
agreed: true,
},
{
title: "Agreement #2",
agreed: false,
},
];
https://plnkr.co/edit/xWdro1SCUTeLbRVbEMWi?p=preview

Why does the Ajax not updating the model correctly?

I am new to angularjs and is using code sample in book "pro-angularjs" to do some test run (it has an initial list of items, but then use Ajax to update list):
<!DOCTYPE html>
<html ng-app="todoApp">
<head>
<title>TO DO List</title>
<link href="bootstrap.css" rel="stylesheet" />
<link href="bootstrap-theme.css" rel="stylesheet" />
<script src="angular.js"></script>
<script>
var model = {
user: "Adam",
items: [{ action: "Buy Flowers", done: false },
{ action: "Get Shoes", done: false },
{ action: "Collect Tickets", done: true },
{ action: "Call Joe", done: false }],
};
var todoApp = angular.module("todoApp", []);
todoApp.run(function ($http) {
$http.get("todo.json").then(function successCallback(data) {
model.items = data;
});
});
todoApp.filter("checkedItems", function () {
return function (items, showComplete) {
var resultArr = [];
angular.forEach(items, function (item) {
if (item.done == false || showComplete == true) {
resultArr.push(item);
}
});
return resultArr;
}
});
todoApp.controller("ToDoCtrl", function ($scope) {
$scope.todo = model;
$scope.incompleteCount = function () {
var count = 0;
angular.forEach($scope.todo.items, function (item) {
if (!item.done) { count++ }
});
return count;
}
$scope.warningLevel = function () {
return $scope.incompleteCount() < 3 ? "label-success" : "label-warning";
}
$scope.addNewItem = function (actionText) {
$scope.todo.items.push({ action: actionText, done: false });
}
});
</script>
</head>
<body ng-controller="ToDoCtrl">
<div class="page-header">
<h1>
{{todo.user}}'s To Do List
<span class="label label-default" ng-class="warningLevel()"
ng-hide="incompleteCount() == 0">
{{incompleteCount()}}
</span>
</h1>
</div>
<div class="panel">
<div class="input-group">
<input class="form-control" ng-model="actionText" />
<span class="input-group-btn">
<button class="btn btn-default"
ng-click="addNewItem(actionText)">Add</button>
</span>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Description</th>
<th>Done</th>
</tr>
</thead>
<tbody>
<tr ng-repeat=
"item in todo.items | checkedItems:showComplete | orderBy:'action'">
<td>{{item.action}}</td>
<td><input type="checkbox" ng-model="item.done" /></td>
</tr>
</tbody>
</table>
<div class="checkbox-inline">
<label><input type="checkbox" ng_model="showComplete"> Show Complete</label>
</div>
</div>
</body>
</html>
the only change i made was:
todoApp.run(function ($http) {
$http.get("todo.json").then(function successCallback(data) {
model.items = data;
});
});
it was initially:
$http.get("todo.json").success(function (data) {
model.items = data;
});
which does not run with the latetest version angularjs, and so i made the change.
when debugging, i found that the initial value of model.items is:
and it is correctly showing in UI (see left side of screenshot).
After the ajax, its value is updated to 'data' whose value is:
the value of data looks fine to me (same as initial value of items).
But after i let go the debugger, finally in UI all items are gone.
I do understand why? it seems 'items' is the same as 'data'. Anyone has a clue on how i can debug further to find out the root cause?
Thanks,
btw, the 'todo.json' i used is below:
[{ "action": "Buy Flowers", "done": false },
{ "action": "Get Shoes", "done": false },
{ "action": "Collect Tickets", "done": true },
{ "action": "Call Joe", "done": false }]
You are not updating your model correctly. As you can see from your screenshot, data contains an object data which should be assigned to your model.
todoApp.run(function ($http) {
$http.get("todo.json").then(function successCallback(data) {
model.items = data.data;
});
});

ng-click in a ng-repeat within a directive

I have a directive with a template to show a table of persons (name, nationality, dates and a button Details). When the button Details is clicked and alert is displayed. The problem is that I don't know how to make the ng-click of the button to work in the ng-repeat inside the directive. They told me to use the following configuration for the directive, using the show function from the controller for the ng-click:
angular.module('app', []).directive('persons', function() {
return {
restrict: 'E',
scope: {
data: '=',
action: '&'
},
template: '...'
};
});
The controller:
angular.module('app', []).controller('labController', [function() {
var vm = this;
vm.persons = [{
name: 'Mark Twatin',
nationality: 'American',
dates: '1835-1910'
}, {
name: 'A. A. Milne',
nationality: 'English',
dates: '1882-1956'
}, {
name: 'Ernest Hemingway',
nationality: 'American',
dates: '1899-1961'
}, {
name: 'Charles Dickens',
nationality: 'English',
dates: '1812-1870'
}, {
name: 'Jane Austen',
nationality: 'English',
dates: '1775-1817'
}];
vm.show = show;
function show(person) {
alert('Show details for: ' + person.name);
}
}]);
So I added the following template:
<table class="table">
<thead>
<th>Name</th>
<th>Nationality</th>
<th>Dates</th>
<th></th>
</thead>
<tbody>
<tr ng-repeat="person in data">
<td>{{person.name}}</td>
<td>{{person.nationality}}</td>
<td>{{person.dates}}</td>
<td>
<input
type="button"
ng-click="action(person)"
value="Details"
class="btn btn-primary"
/>
</td>
</tr>
</tbody>
</table>
And the HTML:
<body ng-app="app">
<div class="container" ng-controller="labController as vm">
<h1>Directives</h1>
<persons data="vm.persons"></persons>
</div>
</body>
So, how can I make the button Details work?
I've created the following fiddle: http://jsfiddle.net/6xyztpxt/3/
You need to change your call inside of the directive for the ngClick.
In a directive, if you want to call a bound function with parameters, you need to pass it an object with to parameters.
Change the ng-click in the template to this: ng-click="action({person: person})"
That means, call the action bounded function with a parameter person that has the value of the current person in the ngRepeat.
Then you need to bind your controller show function to the directive like so:
<persons data="vm.persons" action="vm.show(person)"></persons>
That means, bind the vm.show function as the action to the directive, and when is called pass a parameter person to it.
I have updated your fiddle: http://jsfiddle.net/gmm8a06q/1/
I've made some changes to your fiddle. I've changed the directive scope for action to '=', so you can access directly to the controller method "show".
scope: {
data: '=',
action: '='
},
http://jsfiddle.net/6xyztpxt/6/

Loop through the JSON file which has a unique ID with ng-repeat

I have trouble looping a JSON file. Ng-repeat through the data array where each field has a unique id.
var fullData = {
data: [{
505: {
price: "505",
source: "Amazon"
},
456: {
price: "4555",
source: "Jet"
}
}]
}
<div ng-repeat="data in fullData.data">
{{ data[$index]}}
</div>
This solution dosent seem to work.
Try like this.
var app = angular.module('app',[])
app.controller('ctrl',function($scope){
$scope.data = {
data: [{
505: {
price: "505",
source: "Amazon"
},
456: {
price: "4555",
source: "Jet"
}
}]
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div ng-repeat="(key,value) in data.data">
<div ng-repeat="(k,v) in value">
{{v.price}}:
{{v.source}}
</div>
</div>
</div>
You should use $scope variable in controller to bind the data, change your code like this,
Controller
app.controller("DemoCtrl", ["$scope",
function($scope) {
$scope.fullData = {
data: [{
505: {
price: "505",
source: "Amazon"
},
456: {
price: "4555",
source: "Jet"
}
}]
}
}
]);
HTML
<body ng-app='app'>
<div class="media-list" ng-controller="DemoCtrl">
<div ng-repeat=" data in fullData.data ">
{{data}}
</div>
</div>
</body>
DEMO
as I mentioned in comment dont use
var fulData
use
$scope.fullData
this will automatically bind the value in view
as you did
{{ data[$index]}}
is not the way to access in ng-repeat data itself is enough to access as like this
<div ng-repeat="data in fullData.data">
{{$index}}
{{ data}}
</div>
here is js code
$scope.fullData = {
data: [{
505: {
price: "505",
source: "Amazon"
},
456: {
price: "4555",
source: "Jet"
}
}]
}
working demo http://codepen.io/vkvicky-vasudev/pen/yaEEyv

How to implement PhoneJS SlideOut with AngularJS?

I tried the following code:
var app = angular.module('app', ['ngRoute', 'dx'])
app.controller('IndexCtrl', function($scope){
var contacts = [
{ name: "Barbara J. Coggins", phone: "512-964-2757", email: "BarbaraJCoggins#rhyta.com", category: "Family" },
{ name: "Carol M. Das", phone: "360-684-1334", email: "CarolMDas#jourrapide.com", category: "Friends" },
{ name: "Janet R. Skinner", phone: "520-573-7903", email: "JanetRSkinner#jourrapide.com", category: "Work" }
];
$scope.slideOutOptions = {
dataSource: contacts,
itemTemplate: 'item',
menuItemTemlate: 'menuItem'
}
})
<!-- HTML -->
<div class="app-index" ng-controller="IndexCtrl">
<div dx-slideout="slideOutOptions">
<div data-options="dxTemplate: { name: 'item' }">
<h1 data-bind="text: category"></h1>
<p><b>Name:</b> <span data-bind="text: name"></span></p>
<p><b>Phone:</b> <span data-bind="text: phone"></span></p>
<p><b>e-mail:</b> <span data-bind="text: email"></span></p>
</div>
<div data-options="dxTemplate: { name: 'menuItem' }">
<b data-bind="text: name"></b>
</div>
</div>
</div>
AngularJS there is not enough documentation on the DevExpress site. there are only examples using Knockout. Checkout PhoneJS DXSlideOut Documentation
The problem is in the HTML templates. You should use Angular syntax there.
<div dx-slideout="slideOutOptions">
<div data-options="dxTemplate: { name: 'item' }">
<h1>{{category}}</h1>
<p><b>Name:</b> <span>{{name}}</span></p>
<p><b>Phone:</b> <span>{{phone}}</span></p>
<p><b>e-mail:</b> <span>{{email}}</span></p>
</div>
<div data-options="dxTemplate: { name: 'menuItem' }">
<b>{{name}}</b>
</div>
</div>
Checkout docs about Angular approach.

Resources