Angular print service timeout issue for multiple print - angularjs

var userServicePromise = UserService.printBarCodes(sampleId);
userServicePromise.then(function(response) {
if (response != null && response.data != null && response.data.result != null) {
response.data.result.forEach(function(entry) { //three values in the array, iteraring three times.
$timeout(function() {
vm.barCodeImage = angular.copy(entry);
$timeout(function() {
PrintService.printElement("printThisElement"); // display one value three times
}, 1);
}, 2);
});
} else {
toaster.error(response.data.message);
}
});
using print service to print the div, values of the div are populated using the variable(vm.barCodeImage).
But here one value is displaying all the time in the print. tried adding time out interval after the for each, but no luck.
//print service code
(function() {
'use strict';
angular.module('app.services')
.factory('PrintService', PrintService);
PrintService.$inject = [];
function PrintService() {
var service = {
printElement: printElement
};
return service;
function printElement(elem) {
var printSection = document.getElementById('printSection');
// if there is no printing section, create one
if (!printSection) {
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
}
var elemToPrint = document.getElementById(elem);
// clones the element you want to print
var domClone = elemToPrint.cloneNode(true);
printSection.innerHTML = '';
printSection.appendChild(domClone);
window.print();
window.onafterprint = function() {
printSection.innerHTML = '';
}
};
}
})();
The expected result for this should be three different print(suppose loop size is 3, it should be 7858,7859,7860), but here it displays all same.
printThisElement id is an HTML.
<div id="printThisElement" class="onlyprint" >
<table>
<tr>
<td>{{ ctrl.instCode }}</td>
<td align="center">{{ ctrl.date | dateDisplayFilter}} </td>
</tr>
<tr>
<td colspan="2" align="center"> <img ng-src="data:image/JPEG;base64,{{ctrl.barCodeImage}}"> </td>
</tr>
<tr>
<td colspan="2" align="center">{{ ctrl.user.name }} </td>
</tr>
<tr>
<td >Reg Id: {{ ctrl.regIdLookup }}</td>
<td align="center">{{ ctrl.testName }}</td>
</tr>
</table>
</div>

Ok, I supposed your binding is wrong. printThisElement refer to single data in controller. So if you have multiple entries, it must be an array.
I suggest to you to use a directive instead of a service to print element in DOM.
I create a little plunker to illustrate it : https://plnkr.co/edit/QvmqV88wZCYbsehMWh3W?p=preview
This plunker show how from an array resulting of calling an async service you can display all entries.
The directive is very simple :
.directive('print', function() {
return {
restrict: 'E',
scope: {
data: '='
},
template: '<div id="printThisElement" class="onlyprint" ><table><tr> <td>{{ data.instCode }}</td></tr><tr><td>... Other values in data ...</td></tr></table></div>',
}
})
The template of the directive is your printThisElement id. With this way you can display multiple result isolate by directive.
Hope this will help you
Edit : Solution for the problem was report on this stack Inconsistent Data on multiple page printing on a printer

Related

I am using MVC 4 and angularjs in this actually I want to call an angular js function on page load

i want to invoke angularjs function (DeptSpecific) on page load and am passing ID as the parameter which is hard coded. And that i am passing via ng-init="DeptSpecific('1')". I am learning angularjs please suggest me how to call a function and pass a parameter to it on page load without any click or anything just when a page load a function should be called. If you are thinking why i used ng-init ..there is no specific reason for this it might be wrong but it calls the function well i can see that in debugger (f12) but $scope.s i undefined even though there is a matched ID.
$scope.DeptSpecific = function (ID) {
var BelongsToThisDepartment = [];
$http.get('/Department/getDept').success(function (response) {
$scope.departments = $scope.$eval(response);
});
angular.forEach($scope.departments, function (item1) {
if (item1.ID == ID) {
BelongsToThisDepartment.push(item1);
}
})
$scope.s = $scope.$eval(angular.toJson(BelongsToThisDepartment));
// console.log(JSON.stringify($scope.s));
}
<div ng-app="MyApp">
<div ng-controller="MyController">
<table class="tableData" border="0" cellspacing="0" cellpadding="0" ng-init="DeptSpecific('1')">
<thead>
<tr>
<th></th>
<th>ID</th>
<th>NAME</th>
<th>LOCATION</th>
</tr>
</thead>
<tbody ng-repeat="O in s">
<tr ng-class-even="'even'" ng-class-odd="'odd'">
<td class="CX" ng-click="student(O.ID)"><span>+</span></td>
<td>{{O.ID}}</td>
<td>{{O.Name}}</td>
<td>{{O.Location}}</td>
</tr>
Looking at your code, using ng-init is fine, but your $scope.departments may not be accessible outside of the .success method.
angular.module('MyApp')
.controller('MyController', ['$scope', function($scope) {
$scope.DeptSpecific = function (ID) {
var BelongsToThisDepartment = [];
$http.get('/Department/getDept')
.success(function (response) {
$scope.departments = $scope.$eval(response);
angular.forEach($scope.departments, function (item1) {
if (item1.ID == ID) {
BelongsToThisDepartment.push(item1);
}
})
$scope.s = $scope.$eval(angular.toJson(BelongsToThisDepartment));
console.log($scope.s);
});
}
}]);
now if that works for you but you also want to be able to access $scope.s outside of that .success;
You can write a function, add it into .success pass the value returned onSucess, and do what you want to do.
.success(function(response) {
callAFunction(response);
}

Bind data from pagination to filter in Angular

I have a simple pagination with letters:
<div ng-controller="DataController">
<ul class="pagination">
<li ng-repeat="letter in data_letters">
{{letter}}
</li>
</ul>
<table class="table table-striped">
<tbody>
<tr>
<th>Name</th>
<th>State</th>
</tr>
<tr ng-repeat="person in persons | startsWithLetter:letter">
<td>{{person.Name}}</td>
<td>{{person.State}}</td>
</tr>
</tbody>
</table>
</div>
What is the easiest way to bind the letter (on which we clicked at the paginaton) to the table filter.
Here is a fully functional plunkr: http://plnkr.co/edit/Trr5LzrcMfZqonD0jvjX?p=preview
I have everything implemented already. It is just the data-binding which is missing. Any ideas?
One issue with your code is that you are unnecessarily injecting $scope into your filter:
app.filter('startsWithLetter', function($scope) {
should be
app.filter('startsWithLetter', function() {
The other issue is using 'C-D' as a filter value. I would change $scope.data_letters to be an array of objects that contain a key/value pair like this:
$scope.data_letters = [{
key: 'A',
value: "A"
}, {
key: "B",
value: "B"
}, {
key: ['C', 'D'],
value: "C-D"
}];
Then change your check in the filter to evaluate all keys, like this:
angular.forEach(letters, function(letter, key) {
if (itemName.startsWith(letter)) {
filtered.push(items[i]);
}
});
You can see it working here where I forked your plunk.
Updated your plunk here
Problem was that your filter was not recognized by angular.
Also, I would suggest using
Chrome Developer Tools
it shows useful debug information
app.filter('startsWithLetter', function() {
console.log("Inside startsWithLetter");
return function(items, letter) {
console.log("Inside Filter: Starts with " + letter);
var filtered = [];
for (var i = 0; i < items.length; i++) {
var itemName = items[i].Name;
if (itemName.startsWith(letter)) {
filtered.push(items[i]);
}
}
return filtered;
};
});

Filtering AngularJS Table Based Off Value In Separate Controller

Ok so I am very new to Angular, only been playing with it for three days now. I am running into an issue when trying to filter a table I created based on the value of a "select option" in another controller. Basically I have one controller that performs a REST call to populate a "select" menu dynamically. Then I have another controller that makes a separate REST call to populate a table. What I am trying to do is filter the table based off the "value" from the "selected" option. For example if I choose the "option" with a value of "2", the table would filter to only show results with an "ID" of "2". I may be going about this in a completely wrong way but from what I am reading I need to create a "service" to store the "value" of the "option" so that I can reference it in the controller that populates the table. If anyone could provide some incite on how to go about doing this I would greatly appreciate it. Please see my code bellow...
Angular Code
angular.module('restCalls',[])
// Controller for Project REST Call
.controller('displayProj',function($scope, $http) {
$http({type: "GET", url:"http://my_api_call/", headers: { "ACCEPT": "application/json;odata=verbose"}})
.success(function(data) {
$scope.results = data.d.results;
$scope.projects = [];
for(i=0; i < data.d.results.length; i++) {
$scope.projects.push({name: data.d.results[i].Title , id: data.d.results[i].Id});
};
$scope.getSelectedOption = function(value) {
console.log($scope.selectedProject.id);
};
});
})
// Controller for ChargeCode REST Call
.controller('displayCC',function($scope, $http) {
$http({type: "GET", url:"http://my_api_call/", headers: { "ACCEPT": "application/json;odata=verbose"}})
.success(function(data) {
$scope.results = data.d.results;
$scope.projects = [];
for(i=0; i < data.d.results.length; i++) {
$scope.projects.push({id: data.d.results[i].Master_x0020_ID, cc: data.d.results[i].Title, name: data.d.results[i].deltek_x0020_name});
}
})
});
HTML Code
<div data-ng-app="restCalls" class="ng-scope">
<div id="project_menu_select" data-ng-controller="displayProj" class="ng-scope">
<p class="ng-binding">ID of selected project is:​​​​ {{selecteProject.id}} </p>
<select data-ng-model="selectedProject" data-ng-options="project.name for project in projects" class="ng-pristine ng-valid ng-empty form-control ng-touched ng-untouched" data-ng-change="getSelectedOption()">
</select>​ </div>
<div id="charge_codes_table" data-ng-controller="displayCC" class="ng-scope">
<table class="table table-striped">
<thead>
<tr>
<th>Project ID</th>
<th>Charge Code</th>
<th>Deltek Name</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="project in projects">
<td data-ng-if="project.id == (option value)">{{project.id}}</td>
<td data-ng-if="project.id == (option value)">{{project.cc}}</td>
<td data-ng-if="project.id == (option value)">{{project.name}}</td>
</tr>
</tbody>
</table>
</div>
</div>
Anyway you have both table and select option in one page. Better to use single controller for both.
You can also use common parent controller for both of these controllers.
OR
You can use $rootScope to share the variables. Set as $rootScope.selectedValue = 2 from one controller and then you can access this as $rootScope.selectedValue from another controller.
OR
You can use services to share the functions and variables as follows,
app.service("shared", function () {
var selectedOption = {};
return {
getSelectedOption: function () {
return selectedOption;
},
setSelectedOption: function (value) {
selectedOption = value;
}
};
});

ng-table data not showing on page load

I have integrated ngTable into my mean.io stack and I'm having trouble with populating the table on page load. If I select one of the column headers, the data shows up and the table works as advertised.
Here is my html
<table ng-table="tableParams" class="table">
<tbody ng-repeat="p in $data">
<tr id="tr{{p._id}}" ng-class-odd="'odd'" ng-class-even="'even'">
<td class="rowTd" data-title="'Task Code'" sortable="'task_code'">{{p.task_code}}</td>
<td class="rowTd" data-title="'Task Name'" sortable="'task_name'">{{p.task_name}}</td>
<td class="rowTd" ><input type=button id="editRowBtn{{p._id}}" value="edit"
ng-click="setEditId(p._id)"></td>
</tr>
<tr ng-show="editId===p._id" ng-if="editId===p._id">
<td colspan="7" ng-include src="'editRow.html'"></td>
</tr>
</tbody>
</table>
Here is my controller code.
var data = GeneralTasks.query();
$scope.tableParams = new ngTableParams({
page: 1,
count: 10
},{
total: data.length,
getData: function($defer, params) {
params.total(data.length);
$defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
$scope.editId = -1;
$scope.setEditId = function(pid) {
$scope.editId = pid;
};
I am new to using this table so i'm sure there is something i'm overlooking.
Wanted to provide the answer to my question so it may help others. Anytime an item in the table is added or removed, the table must be reloaded. Since $save and $remove invoke a callback function, just inserted the following for updating the table.
$scope.add = function() {
if (!$scope.tasks) $scope.tasks = [];
var task = new GeneralTasks({
task_code: $scope.task_code,
trade: $scope.trade,
task: $scope.task,
task_name: $scope.task_name
});
task.$save(function(response) {
$scope.tasks.push(response);
var data = $scope.tasks;
$scope.tableParams.total(data.length);
$scope.tableParams.reload();
});
this.task_code = this.trade = this.task = this.task_name = '';
};
First i update the $scope list with the response and then update the tables data and length. Then just call reload.
As I've stated earlier, i do this for $save and $remove. Here is the $remove code.
$scope.remove = function(task) {
for (var i in $scope.tasks) {
if ($scope.tasks[i] === task) {
$scope.tasks.splice(i, 1);
}
}
task.$remove();
var data = $scope.tasks;
$scope.tableParams.total(data.length);
$scope.tableParams.reload();
};
I have noticed that when I edit a name in the list and then cancel, the name does not reset. I suppose I should add similar code for the cancel action but I'm lazy and that's the least of my worries for now. :)
Hope this helps someone else.

AngularJs. Ng repeat jquery sortable unexpected behavior

I faced with unexpected behavior while using jquery sortable in conjunction with angular ng repeat directive. I'm trying to sort items inside different columns in a table.
When I'm dragging 1st element of 2nd column to 1st position (or to 2nd position) in 1st column - all is OK, but if I'll try to put 1st element of 2nd column to 3rd or 4th position it just goes away with subsequent elements.
If you would look at json encoded array at the bottom of document you will see that components are correctly sorted.
I would be grateful for any kind of assistance.
Here is live example: http://plnkr.co/edit/j6xMb4vhcUDVk8POjzpW?p=preview
HTML
<div data-ng-app="myApp" data-ng-controller="defaultCtrl">
<table border="1" data-dnd-list="doc">
<tr>
<td data-ng-repeat="column in doc.columns" data-index="{{$index}}" class="column">
<table class="item" style="border:1px solid red; cursor: pointer" width="100%" data-ng-repeat="component in column.components" data-index="{{$index}}">
<tr>
<td style="padding:5px">{{ component.content }}</td>
</tr>
</table>
</td>
</tr>
</table>
{{ doc }}
</div>
JS
var app = angular.module("myApp", []);
app.controller("defaultCtrl", ["$scope", function($scope) {
$scope.doc = {
columns: [
{
components: [
{
content: "1 column 1 component"
},
{
content: "1 column 2 component"
},
{
content: "1 column 3 component"
}
]
},
{
components: [
{
content: "2 column 1 component"
}
]
}
]
}
}]);
app.directive('dndList', function() {
return function(scope, element, attrs) {
var toUpdate;
var oldComponentIndex = -1;
var oldColumnIndex = -1;
scope.$watch(attrs.dndList, function(value) {
toUpdate = value;
console.log("New changes: ", toUpdate);
},true);
$(element[0]).sortable({
items:'.item',
start:function (event, ui) {
var i = $(ui.item);
// on start we define where the item is dragged from
oldComponentIndex = i.attr("data-index");
oldColumnIndex = i.closest(".column").attr("data-index");
},
stop:function (event, ui) {
var i = $(ui.item);
var newComponentIndex = i.index();
var newColumnIndex = i.closest(".column").attr("data-index");
var toMove = toUpdate.columns[oldColumnIndex].components[oldComponentIndex];
toUpdate.columns[oldColumnIndex].components.splice(oldComponentIndex, 1);
toUpdate.columns[newColumnIndex].components.splice(newComponentIndex, 0, toMove);
scope.$apply(scope.doc);
}
})
}
});
OK. I found a solution. The fact is that when you put new item in sortable list, the DOM became unsynchronized with AngularJS. To prevent this you need to remove HTML of new item.
i.remove();
Here is updated plunker. http://plnkr.co/edit/j6xMb4vhcUDVk8POjzpW?p=preview

Resources