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>
Related
I want to have a <select> without using the options binding, and nest the <option> element under an if binding.
The following is what I did (here's also a fiddle), which displays a behavior I wasn't expecting: The if seems to fire for each option selection, whereas what I expected is that it would fire only when adding the options elements to DOM.
Thus, when an option is chosen, it doesn't displayed. Only when choosing the same option again, it renders as it should.
What did I do wrong?
var DogHouseViewModel = function() {
var self = this;
self.allowedNames = ["A", "B", "C"];
self.puppies = ko.observableArray([]);
self.createPuppy = function () {
self.puppies.push(new DogViewModel());
}
self.isNameAlreadyTaken = function (puppyName) {
var puppies = self.puppies();
for (var i = 0; i < puppies.length; i++) {
if (puppies[i].dogName() == puppyName) {
return true;
}
}
return false;
}
self.printPuppiesName = function () {
self.puppies().forEach(function (puppy) {
alert(puppy.dogName())
})
}
}
var DogViewModel = function (dogName) {
var self = this;
self.dogName = ko.observable();
}
vm = new DogHouseViewModel()
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.1.0/knockout-min.js"></script>
<div>
<button data-bind="text: 'create a puppy', click: createPuppy"></button>
<button data-bind="text: 'print puppies names', click: printPuppiesName"></button>
<div data-bind="foreach: puppies">
<select data-bind="value: dogName">
<!-- ko foreach: $parent.allowedNames -->
<!-- ko if: !($root.isNameAlreadyTaken($data)) -->
<option data-bind="value: $data, text: $data"></option>
<!-- /ko -->
<!-- /ko -->
</select>
</div>
</div>
I believe this is what you are trying to do. The problem is that your allowedNames are the values of the options do you can't just remove them from the array. But you can clone the parent array and as it changes compute the array by returning a list of not used values.
I also added a check to make sure we don't accidentally add a puppy object to the puppies array when no names are available.
var DogHouseViewModel = function() {
var self = this;
self.allowedNames = ["A", "B", "C"];
self.puppies = ko.observableArray([]);
self.createPuppy = function() {
var newPuppy = new DogViewModel(self);
if(newPuppy.allowedNames().length > 0) { // Check to see if there are any names left.
self.puppies.push(newPuppy);
}
}
self.removePuppy = function(obj) {
self.puppies.remove(obj);
}
self.printPuppiesName = function() {
self.puppies().forEach(function(puppy) {
alert(puppy.dogName())
})
}
}
var DogViewModel = function(parent) {
var self = this;
self.dogName = ko.observable();
self.allowedNames = ko.computed(function() {
var allowedNamesClone = parent.allowedNames.slice(0);
var usedNames = parent.puppies().filter(function(pup) { // get all pups who have a name
return pup.dogName() !== '' && pup.dogName() !== self.dogName();
})
usedNames.forEach(function(pup) {
var index = allowedNamesClone.indexOf(pup.dogName());
if (index > -1) {
allowedNamesClone.splice(index, 1); // remove name from cloned array
}
})
return allowedNamesClone; // return new array
})
}
vm = new DogHouseViewModel()
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div>
<button data-bind="text: 'create a puppy', click: createPuppy"></button>
<button data-bind="text: 'print puppies names', click: printPuppiesName"></button>
<div data-bind="foreach: puppies">
<!-- ko if: allowedNames().length > 0 -->
<select data-bind="options: allowedNames, value: dogName"></select>
<button data-bind="click: $root.removePuppy">x</button>
<!-- /ko -->
</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 have trying to load html page in to div in another view using jquery load.
$("#sideMenuCustomerDivition").click(function (e) {
e.preventDefault();
$('#subContents').load('Main/Customer');
});
This is my html
<div class="contents" id="subContents">
</div>
<!-- CDN JavaScript Links-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<!-- end-->
I have put html table in my other view and trying to load data to that table using angular. But my table display like this
This is my javascript for loaded view
angular.module('myApp', ['smart-table']).controller('safeCtrl', ['$scope', function ($scope) {
var firstnames = ['Laurent', 'Blandine', 'Olivier', 'Max'];
var lastnames = ['Renard', 'Faivre', 'Frere', 'Eponge'];
var dates = ['1987-05-21', '1987-04-25', '1955-08-27', '1966-06-06'];
var id = 1;
function generateRandomItem(id) {
var firstname = firstnames[Math.floor(Math.random() * 3)];
var lastname = lastnames[Math.floor(Math.random() * 3)];
var birthdate = dates[Math.floor(Math.random() * 3)];
var balance = Math.floor(Math.random() * 2000);
return {
id: id,
firstName: firstname,
lastName: lastname,
birthDate: new Date(birthdate),
balance: balance
}
}
$scope.rowCollection = [];
for (id; id < 5; id++) {
$scope.rowCollection.push(generateRandomItem(id));
}
//copy the references (you could clone ie angular.copy but then have to go through a dirty checking for the matches)
$scope.displayedCollection = [].concat($scope.rowCollection);
//add to the real data holder
$scope.addRandomItem = function addRandomItem() {
$scope.rowCollection.push(generateRandomItem(id));
id++;
};
//remove to the real data holder
$scope.removeItem = function removeItem(row) {
var index = $scope.rowCollection.indexOf(row);
if (index !== -1) {
$scope.rowCollection.splice(index, 1);
}
}
}]);
and this is html
<table st-table="rowCollection" class="table table-striped">
<thead>
<tr>
<th>first name</th>
<th>last name</th>
<th>birth date</th>
<th>balance</th>
<th>email</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rowCollection">
<td>{{row.firstName}}</td>
<td>{{row.lastName}}</td>
<td>{{row.birthDate}}</td>
<td>{{row.balance}}</td>
<td>{{row.email}}</td>
</tr>
</tbody>
</table>
<script src="~/Scripts/CustomerView.js"></script>
What I'm trying to do is to get a JSON object from a $http request, requested inside a controller, and build a directive that displays the multiple objects in the JSON object in a grid.
The problem is that when the object arrives, I have to process it in the directive's controller to be able to use it in the template, as such, when the JSON object changes, it is not reflected in the template. How can I make the directive know about a change in the object and force it to reload the template?
// The Directive code
amobile.directive('grid', function() {
return {
restrict: 'E',
scope: {
break: '=break',
source: '=source'
},
controller: function($scope) {
var source = $scope.source;
$scope.final_data = new Array(source.length);
if(source){
for(var j=0; j < source.length; ++j){
var total = Math.ceil(source[j]['Division'].length / $scope.break);
var data = new Array(total);
for (var i = 0; i < total; ++i) {
data[i] = source[j]['Division'].slice(i * $scope.break, (i + 1) * $scope.break);
}
$scope.final_data[j] = data;
}
}
},
templateUrl:'directives/grid.tpl.html',
replace: true
};
});
//The template
<div ng-repeat="data in final_data">
<div layout="vertical" layout-sm="horizontal" layout-padding class="" ng-repeat="row in data">
<div class="" ng-repeat="item in row">
<div flex style="width:100px">
{{item.name}}
</div>
</div>
</div>
//index.html
<div ng-controller="DivisionsCtrl as div">
<material-button ng-click="div.go()" class="material-theme-red">Button</material-button>
<div ng-if="div.data.floors">
<gridy break="3" source="div.data.floors"/>
</div>
the simplest solution would be to use watch
controller: function($scope) {
processData = function () {
var source = $scope.source;
$scope.final_data = new Array(source.length);
if(source){
for(var j=0; j < source.length; ++j){
var total = Math.ceil(source[j]['Division'].length / $scope.break);
var data = new Array(total);
for (var i = 0; i < total; ++i) {
data[i] = source[j]['Division'].slice(i * $scope.break, (i + 1) * $scope.break);
}
$scope.final_data[j] = data;
}
}
}
$scope.$watch('div.data.floors', processData, true)
},
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();
},