I'm trying to retrieve some data from a service using Angularjs. Initially, I want to just show the first 10 elements. Then, when the user clicks on a button (with ng-click="next()"), I want the same function to be triggered again in order to get the next 10 elements.
Here's my controller:
Admin.controller('orders', function ($scope, $http) {
var startIndex = 0;
const count = 10;
function retrieveData(startIndex, count) {
$http({
method: 'POST',
url: '/Admin/order/GetOrders',
data: { "startIndex": startIndex, "count": count }
})
.success(function (data) {
$scope.orders = data;
startIndex = startIndex + count;
$scope.$apply();
});
};
retrieveData(startIndex, count);
$scope.next = retrieveData(startIndex, count);
};
Now, what happens is that the function retrieveData() works perfectly the first time, but when I click the button nothing happens. I know for sure that the "click" event triggers the function, because I tried to replace the code with an alert, but I don't understand why the function retrieveData() itself only works the first time.
What am I missing?
<div class="container admin" ng-controller="orders">
<table class="table">
<tbody>
<tr ng-repeat="order in orders| filter:{OrderStatus: 'Hto'} | filter:query | filter:'!'+showCancelled | orderBy:predicate:reverse">
<td>
{{order.UserName}}
</td>
<td>
<span ng-class="{ 'label label-danger' : isLate }">
{{order.OrderDate}}
</span>
</td>
<td>
{{order.Country}}
</td>
<td>
<span ng-class="{ 'label label-warning' : order.OrderStatus == 'HtoPreAuth' || order.OrderStatus == 'SalePreAuth'}">
{{order.OrderStatus}}
</span>
</td>
</tr>
</tbody>
</table>
<a href="" ng-click="retrieveData()">
next
</a>
</div>
You are supposed to make the changes inside the $apply method:
Admin.controller('orders', function ($scope, $http) {
var startIndex = 0;
const count = 10;
$scope.retrieveData() { // No parameters
$http({
method: 'POST',
url: '/Admin/order/GetOrders',
data: { "startIndex": startIndex, "count": count }
})
.success(function (data) {
startIndex = startIndex + count;
$scope.orders = data;
if(!$scope.$$phase) {
$scope.$digest();
}
});
}
$scope.retrieveData();
};
// And the view
<a ng-click="retrieveData()"></a>
Edit:
Remove the parameters from the $scope.retrieveData function since they will be undefined
if you call the function with ng-click="retrieveData()"
Related
I have a table of dynamically generated data with nodejs and have to modify it like an excel in the browser. I have the element that interest me (the first one passed) but also the rest of the whole table which doesn't interest me. How can I make it stop? I've tried e.stopPropagation()
My generated table, I've only worked with "denomination for the moment
<% for (var i=0; i<nomenclature.length; i++){ %>
<tr>
<td>
<a class="bouton" href="/nomenclature/<%= nomenclature[i].idPiece %> ">Ajout bon de commande</a>
</td>
<td id="idPiece<%=i%>" name="idPiece">
<%=nomenclature[i].idPiece %>
</td>
<td contenteditable='true' id="denomination<%=i%>" class="denomination1">
<%=nomenclature[i].denomination %>
</td>
<td contenteditable='true' class="n_piece_plan">
<%=nomenclature[i].n_piece_plan %>
</td>
<td contenteditable='true'>
<%=nomenclature[i].rev %>
</td>
<td contenteditable='true'>
<%=nomenclature[i].qte %>
</td>
<td contenteditable='true'>
<%=nomenclature[i].unite %>
</td>
<td contenteditable='true'>
<%=nomenclature[i].matiere %>
</td>
</tr><script>
My script see below
</script>
<% } %>
</table>
My script in ejs
var all = document.getElementsByTagName("td");
for (var j=1; j<all.length;j++){
all[j].addEventListener("input", function(e) {
const newData = this.innerHTML;
const myID = document.getElementById("idPiece<%=i%>").innerHTML;
const myColumn = this.className;
const data = {newData, myID, myColumn};
const options = {
method: 'POST',
headers: {
'Content-Type':'application/json'
},
body: JSON.stringify(data)
};
fetch('./nomenclature/inter/modification', options);
e.stopPropagation();
}, false);
}
My controller
exports.nomenclatureModification = function(request, response){
let newData = request.body.newData;
let myID = request.body.myID;
newData = newData.replace(/(\r\n|\n|\r|\s)/gm,"");
myID = myID.replace(/(\r\n|\n|\r|\s)/gm,"");
let myColumn = request.body.myColumn;
console.log(newData +" ahiiiiii "+ myColumn +" rooooh "+ myID);
/*
connection.query('UPDATE nomenclature SET ?? = ? WHERE idPiece = ?;',[myColumn,newData,myID], function(error, resultSQL){
if (error) throw error;
else{
console.log("modif enregistrer en bdd");
}
});
*/
response.redirect('/nomenclature');
}
The first element passed thru the console.log is the one I've modified and so my sql query can be made with that one (I can change easily every column). But because my script is nested inside the loop (to obtain idPiece[i] of my changed row) it also prints out the rest which I would like to stop.
EDIT: found a solution:
got the script out of the loop
changed my table with a id for each
<td contenteditable='true' id="<%=i%>" class="n_piece_plan">
<%=nomenclature[i].n_piece_plan %>
</td>
script change to access that id
for (var j=0; j<all.length;j++){
all[j].addEventListener("input", function(e) {
const newData = this.innerHTML;
let stringID = 'idPiece' + this.id;
const myID = document.getElementById(stringID).innerHTML;
const myColumn = this.className;
const data = {newData, myID, myColumn};
const options = {
method: 'POST',
headers: {
'Content-Type':'application/json'
},
body: JSON.stringify(data)
};
fetch('./nomenclature/inter/modification', options);
e.stopPropagation();
}, false);
}
I can now modify my table in the browser exactly like an Excel table and update that in my db. Performance is ok.
I got progress bar in my table where I show how many hours has been spend on project. When I click on some tab, currentTab method is fired to get data from database and after I promise is resolved my TimeService function is fired also to calculate hours for progress bar, but when angular .css() is reached it doesnt update my progress bar at all and I dont know why since it definitely 100% working code. Is there some feature in mdTabs which prevent this?
HTML code below, I deleted plenty of stuff to make it more readable
<md-tab label="Testing" md-on-select="currentTab('Testing')">
<md-content class="md-padding">
<table id="projects-active" class="table table-bordered table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Estimated time</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="project in projects.Data">
<td>{{project.Id}}</td>
<td>{{project.Name}}</td>
<td>{{project.Description}}</td>
<td>
<div class="progress-group">
<div class="progress sm">
<div class="progress-bar progress-bar-success progress-bar-striped" id="progress-bar-pId-{{project.Id}}">
</div>
</div>
</div>
</td>
<td>{{project.Status}}</td>
</tr>
</tbody>
</table>
<div class="box-footer clearfix">
<ul uib-pagination total-items="totalItems"
items-per-page="maxSize"
ng-model="currentPage"
max-size="maxSize"
class="pagination-sm"
boundary-links="true"
num-pages="pages"
ng-change="setPage(currentPage, 'Testing')"></ul>
</div>
</md-content>
Here is my function in TimeService modul
projectProgressArray: function (array) {
var items = array.Data;
angular.forEach(items, function (key, value) {
var id = key.Id;
var maxTime = key.EstimatedTime;
var currentTime = key.TimeSpend;
var percentageComplete = Math.round(((currentTime / maxTime) * PERCENTAGE) * 100) / 100;
if (!("#progress-bar-pId-" + id).length == 0) {
angular.element("#progress-bar-pId-" + id).css("width", percentageComplete + "%");
if (percentageComplete > 100) {
angular.element("#progress-bar-pId-" + id).removeClass("progress-bar-success");
angular.element("#progress-bar-pId-" + id).addClass("progress-bar-danger");
}
}
});
Here is my controller function where I fetch data to my data tables
var MAX_SIZE_PER_PAGE = 5;
$scope.currentPage = 1;
$scope.maxSize = MAX_SIZE_PER_PAGE;
$scope.pages = 0;
$scope.totalItems = 0;
$scope.setPage = function (pageNo, status) {
$scope.currentPage = pageNo;
$scope.projects = ProjectService.queryPaged({ pageSize: $scope.maxSize, pageNumber: $scope.currentPage, status: status });
$scope.projects.$promise.then(function (data) {
setTimeout(function () {
TimeService.projectProgressArray($scope.projects);
}, 0);
});
};
$scope.currentTab = function (status) {
$scope.projects = ProjectService.queryPaged({ pageSize: $scope.maxSize, pageNumber: 1, status: status });
$scope.projects.$promise.then(function (data) {
$scope.totalItems = data.TotalCount;
setTimeout(function () {
TimeService.projectProgressArray($scope.projects);
}, 0);
});
}
UPDATE: I added image where i copy progress bars outside of md-tab to show its working outside of md-tabs but not inside it.
So after some time of I found out that I cannot manipulate with css in Angular material using angular.element().css() method. I had to edit my TimeService method where I created array filled with information about single progress bar per project and send it back to my controller and use ng-style
to manipulate with my css inside ng-material DOM
projectProgressArray: function (array) {
var progressBarArray = [];
var items = array.Data;
angular.forEach(items, function (key, value) {
var progressBar = {
projectId: null,
percentage: null,
barClass: null
}
var id = key.Id;
var maxTime = key.EstimatedTime;
var currentTime = key.TimeSpend;
var percentageComplete = Math.round(((currentTime / maxTime) * PERCENTAGE) * 100) / 100;
progressBar.projectId = id;
progressBar.percentage = percentageComplete + "%";
if (!("#progress-bar-pId-" + id).length == 0) {
if (percentageComplete > 100) {
progressBar.barClass = "progress-bar-danger";
}
else {
progressBar.barClass = "progress-bar-success";
}
}
progressBarArray.push(progressBar);
});
return progressBarArray;
Reworked HTML binding
<div class="progress-group">
<div class="progress sm" ng-repeat="item in progressBars" ng-hide="item.projectId != project.Id">
<div ng-class="{'progress-bar-success': item.barClass == 'progress-bar-success',
'progress-bar-danger': item.barClass == 'progress-bar-danger' }"
class="progress-bar progress-bar-success progress-bar-striped" id="progress-bar-pId-{{project.Id}}"
ng-style="{'width':item.percentage}">
</div>
</div>
Recently I create a AngularJs App . Thats code are below
HTML :
<div ng-app="" ng-controller="Hello">
<ul>
<li ng-repeat="x in greeting">
{{ x.user_name }}
</li>
</ul>
</div>
And my JS code is:
function Hello($scope, $http) {
$http.get('http://localhost/google/cibl/dashboard/get_all_user').
success(function(data) {
$scope.greeting = data;
});
}
Its working fine. This http service give me 2000 row now i want to paginate this by AngularJs. How can I do that ?
In your controller
app.controller('Hello', function($scope){
$scope.pageSize = 10;
$scope.currentPage = 0;
$scope.changePage = function(page){
$scope.currentPage = page;
}
})
In your mark up, you should have
<div ng-app="" ng-controller="Hello">
<ul>
<li ng-repeat="x in greeting | startFrom: currentPage * pageSize | limitTo: pageSize">
{{ x.user_name }}
</li>
</ul>
</div>
We're missing the startFrom filter so lets create that
app.filter('startFrom', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
Now all thats left is the paginating panel, I'll leave it up to you to pretty it with css
<ul class="pagination" >
<li ng-repeat="page in pagination" ng-class="{'active':currentPage == page}"><a ng-click="changePage(page)">{{page + 1}}</a></li>
</ul>
Notes:
The reason why we use changePage() instead of currentPage = page is due to ng-repeat which could break some of the variables
In your anchor () tag, instead of ng-click, you can use a href to mark the page and in your controller, watch the page ref and change based on the queries. The benefits to this is that when you decide to do SEO for your website, it will be ready for that!
href="#!/partialname?page={{page}}"
You can do this way:
Pagination Example: http://jsfiddle.net/2ZzZB/56/
Found it in this question:
Pagination on a list using ng-repeat
At least I got a solution and its work properly :
HTML :
<div ng-controller="userController" class="jumbotron">
<h2>User List</h2>
<table class="table table-striped">
<thead>
<tr>
<th>User </th>
<th>Group</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="u in users | itemsPerPage : 5">
<td>{{u.user_name}}</td>
<td>{{u.user_type}}</td>
</tr>
</tbody>
</table>
<dir-pagination-controls on-page-change="pageChanged(current)" template-url="<?php echo base_url(); ?>js/dirPagination.tpl.html"></dir-pagination-controls>
</div>
and JS :
Here i use AngularJs pagination directive
function userController($scope, $http) {
$scope.users = [];
$scope.total = 0;
$scope.perPage = 25; // this should match however many results your API puts on one page
getUsers(1);
$scope.pagination = {
current: 1
};
$scope.pageChanged = function (newPage) {
getUsers(newPage);
};
function getUsers(pageNumber) {
// this is just an example, in reality this stuff should be in a service
$http.get(app.baseUrl + 'dashboard/get_all_user/' + pageNumber)
.success(function (data) {
console.log(data);
$scope.users = data.users;
$scope.total = data.total;
})
.error(function (data) {
console.log(data);
alert("There was a problem. Please try again later.");
});
}
};
var myApp = angular.module('myApp', ['angularUtils.directives.dirPagination']);
var app = app || {};
app.baseUrl = '<?= base_url() ?>';
myApp.controller('userController', userController);
I wanted reload a core-list element to show new data, but it´s not refreshing.
I re-call the JS function thats generate the data but doesn t work... and reload like a 'normal' div doesn t work either! The list only shows the new data if i reload the entire page...
function values(sender, textomsg, datacriacao, senderfoto){
var sender2 = sender.split(",");
var textomsg2 = textomsg.split(",");
var datacriacao2 = datacriacao.split(",");
var senderfoto2 = senderfoto.split(",");
var namegen = {
generateString: function (inLength) {
var s = '';
for (var i = 0; i < inLength; i++) {
s += String.fromCharCode(Math.floor(Math.random() * 26) + 97);
}
return s;
},
generateName: function (inMin, inMax) {
return this.generateString(Math.floor(Math.random() * (inMax - inMin + 1) + inMin));
}
};
Polymer('list-test', {
count: sender.length,
ready: function () {
this.data = this.generateData();
},
generateData: function () {
var names = [], data = [];
for (var i = 0; i < this.count; i++) {
names.push(namegen.generateName(4, 8));
}
names.sort();
for (var i = 0; i < this.count; i++) {
data.push({
index: i,
sender: sender2[i],
textomsg: textomsg2[i],
datacriacao: datacriacao2[i],
senderfoto: senderfoto2[i]
});
}
return data;
},
tapAction: function (e) {
console.log('tap', e);
}
});
}
<%----%>
<template id="templateConversas" runat="server">
<div id="item" class="item {{ {selected: selected} | tokenList }}" ><%--onClick="conversa('{{name}}');"--%>
<div class="message" style="background-image: url({{senderfoto}});">
<span class="from"><br/>{{sender}}</span>
<span class="timestamp">{{datacriacao}}</span>
<div class="subject"><br/>{{textomsg}} </div><%--------Infinite List. {{index}}--%>
<%--<div class="body"><br/>Mensagem de teste...........</div>--%>
</div>
</div>
</template>
The problem is also reload the 'list-test'. if i call the js function after the list is loaded it doesn't apply the new data...
Your code isn't complete so it is hard to understand but I think that the problem is that you don't assign the result of the generateData() function to the template's model. Try following script for your component
Polymer('list-test', {
created: function () {
this.data = [];
},
refresh: function () {
this.data = this.generateData();
},
generateData: function () {
// your original code here
}
});
Now the list content should be updated with newly generated data when you call refresh() of the list-test element. To fill the list when element is created add
ready: function () {
this.refresh();
},
Is there any way to do a requirejs define in a text document? Or an html document?
I have a document filled with header and cell templates for a grid
<body>
<th data-fieldname="PatientPerson">Name <span data-bind="attr: { class: sortField() == 'PatientPerson' ? 'inline-block' : 'hide' }"></span></th>
<td><span class="glyphicon glyphicon-expand"></span><a data-bind="click: function () { $parent.loadReportSummary(PatientPerson.ID()) }"><span data-bind="text: PatientPerson.FullName"></span></a></td>
<th data-fieldname="StudyType">Study Type <span data-bind="attr: { class: sortField() == 'StudyType' ? 'inline-block' : 'hide' }"></span></th>
<td data-bind="text: StudyType"></td>
<th data-fieldname="ServiceDate">Service Date<span data-bind="attr: { class: sortField() == 'ServiceDate' ? 'inline-block' : 'hide' }"></span></th>
<td data-bind="text: ServiceDate"></td>
<th>Export Summary</th>
<td><a data-bind="click: function (data) { $parent.exportReportSummary(data, PatientPerson.ID, SummaryID, !StudyExported()) }">View</a></td>
<th>Print All Reports</th>
<td><a data-bind="click: function (data) { $parent.printAllReports('/PrintReports/Reports?summaryID=' + SummaryID) }">Print</a></td>
etc.......
</body>
In another module I have an array which determines which of these columns are used in a knockout computed observable. I was hoping that I could make each of these a module instead of parsing them using jquery, but I wanted them to all be in one file. I'm using the text plugin for requirejs, but there seems to be no way to declare each of these as a module inside of one file, and it seems wasteful to have to split each of these into separate files.
maybe something like
<!--export name:"PatientPerson" -->
<th data-fieldname="PatientPerson">Name <span data-bind="attr: { class: sortField() == 'PatientPerson' ? 'inline-block' : 'hide' }"></span></th>
<td><span class="glyphicon glyphicon-expand"></span><a data-bind="click: function () { $parent.loadReportSummary(PatientPerson.ID()) }"><span data-bind="text: PatientPerson.FullName"></span></a></td>
<!-- /export-->
Then referencing the module like
require('filename').PatientPerson;
I created a plugin where you can add a !define to the end of the require on some file, and it will make the spec suggested from the OP work. It works with the official text plugin for requirejs.
define(['text', 'module'], function (text, module) {
var exportRegExp = /<!--\s*?export[^>]*>([\s\S]*?)<!--\s*?\/export\s*?-->/g,
masterConfig = (module.config && module.config()) || {},
buildMap={};
text.export = function (content) {
var exports = null;
if (content) {
var matches = content.match(exportRegExp) || [],
match, _i, _len;
exports = matches.length ? {} : null;
for (_i = 0, _len = matches.length; _i < _len; _i++) {
match = matches[_i];
var exportName = match.match(/(<!--\s*?export\s*?name\:")(.*?)\"\s*?-->/).slice(-1)[0];
exports[exportName] = match.replace(/<!--\s*?export[^>]*>\n?/, '').replace(/<!--\s*?\/export\s*?-->/, '');
}
}
return exports;
};
var baseParseName = text.parseName;
text.parseName = function(name) {
var index, parseExport = false;
index = name.indexOf('!export');
if (index !== -1) {
parseExport = true;
name.split('!export').join('');
}
var out = baseParseName(name);
out["strip"] = { "export": parseExport, "strip": out["strip"] };
return out;
};
text.finishLoad = function (name, strip, content, onLoad) {
var exports = strip.export ? text.export(content,name) : content;
if (exports == null) content = strip.strip ? text.strip(content) : content;
else content = exports;
if (masterConfig.isBuild) {
buildMap[name] = content;
}
onLoad(content);
};
text.write = function (pluginName, moduleName, write, config) {
if (buildMap.hasOwnProperty(moduleName)) {
var content = text.jsEscape(buildMap[moduleName]);
write.asModule(pluginName + "!" + moduleName,
"define(function () { return '" +
content +
"';});\n");
}
};
});
The following will work
require([text!somefile!define],function(){})
This also works but it ignores the !strip command if any exports exist in the file.
require([text!somefile!strip!define],function(){})
then you can call
require(['someModuleNameInDefineComment'],function(){})
I have not handled strip with a beginning define in the header.
Here is a Gist