AngularJs direct infinite Scrolling not working - angularjs

I ve got this view with a ng-repeat :
<div style="overflow: auto; max-height: 550px; min-height:550px;" >
<table class="table table-bordered table-hover " border="1" >
<thead fix-head>
<tr>
<th>Photo</th>
<th>Identifiant</th>
<th>Prénom</th>
<th>Nom</th>
<th>Editer</th>
</tr>
</thead>
<tbody >
<tr ng-repeat="footballeur in footballers| limitTo: limit " >
<td><img ng-src="img/{{footballeur.photo|| 'defaut.png'}}"/></td>
<td>{{footballeur.identifiant}}</td>
<td>{{footballeur.prenom}}</td>
<td>{{footballeur.nom}}</td>
<td><button ng-click="modifier_footballeur(footballeur)" class="btn btn-primary" aria-label="Left Align">Editer</button></td>
</tr>
</tbody>
</table>
<button ng-click="loadMore()">more</div>
And in my controller :
$scope.loadMore = function() {
$scope.limit += 5;
};
The button "more" works very well, so i'm adding 5 footballers to the ng-repeat each time i click on it.
The problem is that i want to detect the end of the div bottom, and start loadMore() each time i reach the bottom.
I've tried 3 directives and full Jquery nothing works and ingnite the loadMore() correctly..
The Jquery detects well the bottom of the div , but refuses to execute loadMore() inside its function even with angular.element syntax...
This next directive detects well the end of the div, but i dont know how to start $scope.loadMore() from it, it doesn't recognize the scope. . Maybe you should have an idea ? thanks a lot :
monApp.directive("scrollable", function() {
return function(scope, element, attrs) {
var container = angular.element(element);
container.bind("scroll", function(evt) {
if (container[0].scrollTop <= 0) {
alert('On the top of the world I\'m singing I\'m dancing.');
}
if (container[0].offsetHeight + container[0].scrollTop >= container[0].scrollHeight) {
alert('On the bottom of the world I\'m waiting.');
$('#liste').scope().loadMore();
}
});
};
})

Related

loading or progress screen appear on click event

I want when click on switchery button the loading screen appear or modal and this loading screen or modal will dismiss only when http request completed and get all data.In short when click on switch then user cannot perform any action and cannot click on other buttons.so how can i do this.I'm using angular with laravel 5.2
<div class="table-responsive">
<table class="table table-hover ">
<thead>
<tr>
<th>Device Name</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="device in devices">
<td>[[device.device_name]]</td>
<td>
<switch id="enabled" name="enabled" on="ON" off="OFF"
ng-init="enabled=device.status" ng-model="enabled" class="green "
ng-change="changeStatus([[device.device_id]],[[device.user_id]],enabled)"
></switch>
</td>
</tr>
</tbody>
</table>
</div><!-- /.table-responsive -->
Angular file
myapp.controller('AutomationController',function(dataFactory,$scope){
$scope.devices;
$scope.userId=null;
loadDevices();
function loadDevices()
{
dataFactory.httpRequest('/user_devices').then(function (data) {
console.log(data);
$scope.devices=data;
})
}
$scope.changeStatus=function($device_id,$user_id,$status){
if($status)
{
$status=1;
}
else {
$status=0;
}
dataFactory.httpRequest('/device_status/'+$device_id,'PUT',{},
{"user_id":$scope.userId,
"status":$status
}).then(function(data) {
});
}
});
Before making your $http request, set $scope.loading = true; and in your promise's finally(function(){}); set $scope.loading = false;
In your HTML template, add something like <div class="modal loading" ng-if="loading">Loading...</div>. Use CSS to make it take up whole screen and have higher z-index so it blocks clicks on the rest of UI.

Setting a table onclick using AngularJS ng-repeat

My static html table has a row click event which hightlights a div.
The static table is working fine, but my ng-repeat table has some issues.
I can now highlight my div with a red border, but how do I remove the border when something else is clicked ?
Here's the static table example :
<script type="text/javascript">
$('.image-clicked').click(function () {
debugger;
$(this).css("border", "2px solid red");
});
$('.clickable_row td div').click(function (e) {
// clear all borders first, highlight clicked image
var imageclicked = $(this).data('url');
$('.propertyTable td div').css("border", "none");
$(this).css("border", "2px solid red");
});
</script>
<table id="gadgets" class="propertyTable clickable_row">
<tr>
<th>Type</th>
</tr>
<tr>
<td data-url="chart_treelist">
<div><img data-draggable id="chart_treelist" src="images2/table.png" title="Tree Grid" alt="Hierarchy Grid" width="64" height="64">Grid</div>
</td>
<td data-url="{chart_pivot}">
<div><img data-draggable id="chart_pivot" src="images2/pivottable.png" title="Pivot Table" alt="Pivot Table" width="64" height="64">Pivot</div>
</td>
</tr>
<tr>
<td>
<div><img data-draggable id="chart_bar" src="images2/bar.png" title="Bar" width="64" height="64">Bar</div>
</td>
<td>
<div><img data-draggable id="chart_line" src="images2/line.fast.png" title="Line" >Line</div>
</td>
</tr>
<tr>
<td>
<img data-draggable id="chart_pie" src="images2/pie.png" title="Pie" alt="Pie" width="64" height="64">Pie
</td>
<td><img data-draggable id="chart_area" src="images2/area.png" title="Area" alt="Area" width="64" height="64">Area</td>
</tr>
<tr>
<td>
<img data-draggable id="chart_scatter" src="images2/point.png" title="Scatter" width="64" height="64">Scatter
</td>
<td>
<img data-draggable id="chart_bubble" src="images2/bubble.png" title="Bubble" width="64" height="64">Bubble
</td>
</tr>
</table>
And here is the AngularJS ng-repeat generated table.
FYI: ng-class assigns the image-border class if the initImage values are equal. ng-click goes into the controller and reassigns the chart based on what was just selected.
PROBLEM: I cannot figure out how to select a NEW chart icon with red border, and simultaneously REMOVE the image-border class on the others.
(function () {
'use strict';
angular.module('rage')
.controller('GadgetIconsCtrl', ['$rootScope', '$scope', icons]);
function icons($rootScope, $scope) {
var gadgets = this;
gadgets.subset = null;
gadgets.chartSelected = null;
gadgets.selectChart = function (chart) {
// the assumption is that user selected a different chart icon from the formatting tab
gadgets.chartSelected = chart;
};
if ($scope.widget.gadgetType == 'chart' && $scope.widget.chartType == 'bar') {
// user is configuring a bar chart type, so we also include 'column' in our subset of icons to display
gadgets.subset = _.filter($scope.widgetDefs, function (item) {
return item.chartType == 'bar' || item.chartType == 'column';
});
}
}; // end of gridSettings()
})();
<style scoped>
.image-clicked {
border: 2px solid red;
}
.image-unclicked {
border: 2px solid red;
}
</style>
<table ng-controller="GadgetIconsCtrl as gadgets" >
<tr ng-repeat="gadget in gadgets.subset" >
<td>
<!-- the image icon for this widget should have a css border, otherwise none -->
<div ng-class="{'image-border': gadget.initImage===widget.initImage}">
<img ng-click="gadgets.selectChart(gadget.name)" ng-src="{{gadget.initImage}}" title="{{gadget.title}}"
width="64" height="64">{{gadget.title}}
</div>
</td>
</tr>
</table>
I'm sure there's a better Angular approach to this, but I'm still trying to figure out the best use of ng-click and ng-class in this use-case.
Help is appreciated.
thanks,
Bob
I started a new plnkr http://plnkr.co/edit/w3Ojy5Eo40QHDtUxJfft
for your question.
You can use ng-clik and inject click event (and affected element) into the handler:
$scope.widgetClick = function($event) {
$event.srcElement.style.border = "2px black solid";
}
Corresponding html:
<div class="image-clicked" ng-click="widgetClick($event)"> ... </div>
For simple dom manipulation, like adding or removing a css class, its better to use angular only instead of mixing things up with jQuery.
Dealing with dom/css changes by yourself is more "jQuery way".
With Angular on the other hand, you will change the data for your model and
let the framework do the dom/css work.
For your example (using my plunkr code):
Define widget for ng-repeat as something like:
{
title : "Foobar ",
initImage : "http://lorempixel.com/10/10/",
clicked: false
}
and change clicked in the handler:
$scope.widgetClick = function(widget) {
widget.clicked = true;
};
Corresponding html:
<div ng-click="widgetClick(widget)" ng-class="{clicked: widget.clicked}">
The css class .clicked will be added by angular if widget.clicked changes to true.
Why this is better? No Css/Dom manipulation in your code. Everything clean and nice.
EDIT:
How to remove the .clicked class from previously selected widget?
We will need to keep a reference to the selected widget in the controller:
var selectedWidget = null;
$scope.widgetClick = function(w) {
if(selectedWidget) selectedWidget.clicked = false;
selectedWidget = w;
w.clicked = true;
};
Now, when another widget is selected (clicked), we only need to update the model data: Set the clicked property on the previously selected widget to false and change it to true on the selected one. And update the reference to the selectedWidget. Angular will take care about the css.
Updated plnkr http://plnkr.co/edit/IqWc1W9N12SH8K72jAun?p=preview
Try this !! cannot run angular now, but I think it should work!
< script type = "text/javascript" >
var lastobj = "";
function clickImage(obj, $event) {
debugger;
if (lastobj != obj) {
$(lastobj).css("border", "0px");
} else {
$($event.target).css("border", "2px solid red");
}
};
function clickRow(obj, $event) {
//obj should be the widget
//There you should do similar..
var imageclicked = $($event.target).data('url');
$('.propertyTable td div').css("border", "none");
$($event.target).css("border", "2px solid red");
}); < /script>
<table ng-controller="GadgetIconsCtrl as gadicons">
<tr ng-repeat="widget in gadicons.widgetSubset">
<td>
<div ng-click="clickRow(widget)" class="image-clicked">
<img data-draggable ng-click="clickImage(widget)" ng-src="{{widget.initImage}}" title="{{widget.title}}" width="64" height="64">{{widget.title}}
</div>
</td>
</tr>
</table>
EDIT
I added the unset border functionality u told, and corrected some spelling and grammar mistakes for angularjs.
Hope it works!!

Having trouble with ellipsis with angularjs

I am having issue with ellipsis and angularjs. I want to update max-width dynamically from parent as TD element width. I tried for 2 approach. One is updating dom after printing the table structure. Another is to provide directive. But nothing works.
HTML:
<table class="table data-table cvcTable sort display">
<thead>
<tr>
<th ng-repeat="column in tableOptions.columnDefs"
ng-style="{'width': column.width}"><a href
ng-click="tableEvents.sort('{{column.field}}',$event)">{{column.label}}
<i class="pull-left" ng-class="column.orderType"></i>
</a></th>
</tr>
</thead>
<tbody>
<tr ng-class-odd="'row-odd'" ng-class-even="'row-even'" ng-repeat="item in tableOptions.data">
<td>{{item.key}}</td>
<td><span title="{{item.value}}" ellipsisSpan
class="ellipsis">{{item.value}}</span></td>
<td><span title="{{item.comments}}" ellipsisSpan
class="ellipsis">{{item.comments}}</span></td>
<td>{{item.updated}}</td>
<td>{{item.updatedBy}}</td>
</tr>
</tbody>
Directive: I am not getting alert message.
app.directive('ellipsisSpan', function () {
return {
restrict: 'A',
link: function ($scope, element, attrs, ctrl) {
alert("Im inside call");
// Do calculation
}
};
});
Dynamic Call: I can see following line working perfectly but don't see updated in DOM.
"a.css('max-width', width + 'px');"
angular.element(document).ready(function () {
var element = angular.element(document.querySelector('.ellipsis'));
angular.forEach(element, function(value, key){
var a = angular.element(value);
var width = a.parent()[0].clientWidth;
a.css('max-width', width + 'px');
});
scope.$apply();
});
CSS:
.ellipsis {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: inherit;
}
Directive names get converted into dash separated case in the HTML so you need to reference your directive like this in the HTML:
<span title="{{item.value}}" ellipsis-span class="ellipsis">

AngularJS does not pass data to JQuery DataTable

I am using datatables from datatables.net and am running into some issues with the AngularJS ng-repeat and values being populated into the table. I have added a button that will pass a value into the table and this works great. However, when I try to add sorting and scroll bar to the table it stops working. I'm not sure what I'm doing wrong here.
html
<div ng-controller="TodoCtrl" id="TodoCtrl">
<table id="example" cellpadding="0" cellspacing="0" border="0" class="display table table-striped table-bordered table-condensed">
<thead>
<tr>
<th>Bus Id</th>
<th>X Cords</th>
<th>Y Cords</th>
<th>Event Type</th>
<th>Time Stamp</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="todo in todos"><td>{{todo.busId}}</td><td>{{todo.xCord}}</td><td>{{todo.yCord}}</td><td>{{todo.eventType}}</td><td>{{todo.timeStamp}}</td></tr>
</tbody>
</table>
<form class="form-horizontal">
<input type="text" ng-model="vbusId" ng-model-instant>
<button class="btn" ng-click="addTodo()"><i class="icon-plus"></i>Add</button>
</div>
jscript
function TodoCtrl($scope) {
$scope.todos = [];
$scope.addTodo = function (vbusId, vxCord, vyCord, vposTimeStamp, veventType) {
$scope.todos.push({busId:'vbusId', xCord:vxCord, yCord:vyCord, timeStamp:vposTimeStamp, eventType:veventType});
}
}
table script
$(document).ready(function() {
$('#example').dataTable( {
"sScrollY": "200px",
"bPaginate": false
} );
} );
If I comment out the table script the dynamic table works and gets populated with the passed data. If i uncomment the table code the table shows up with the sorting and scroll bar but it will not accept the values. Can someone tell what I am missing?
Thanks a bunch!
You need to ensure that the datatables is being called AFTER angular has digested the page. Something like this:
function TodoCtrl($scope, $timeout) {
$scope.todos = [];
$scope.addTodo = function (vbusId, vxCord, vyCord, vposTimeStamp, veventType) {
$scope.todos.push({busId:'vbusId', xCord:vxCord, yCord:vyCord, timeStamp:vposTimeStamp, eventType:veventType});
}
$timeout(function(){
$('#example').dataTable( {
"sScrollY": "200px",
"bPaginate": false
} );
}, 0, false);
}
However, flat mixing of angular and jquery in this way is a terrible idea. You really should be writting an angular directive to wrap the jquery plugin, or just not use jQuery at all.

setting ng-href in <tr> elements

The following code makes the client.name an anchor on each client in clients. I am interested in having the entire <tr> element be that link however. ng-href does not work on the <tr> element.. what can I do so that the entire row is a single link instantiated by ng-href?
<tr ng-repeat="client in clients">
<td><a ng-href="#/user/{{client.tagid}}">{{client.firstname}}</a></td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
What I am looking to do is something like this.. which of course does not work..
<a ng-href="#/user/{{client.tagid}}">
<tr ng-repeat="client in clients">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
</a>
OR
<tr ng-repeat="client in clients" ng-href="#/user/{{client.tagid}}">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
You can use an ng-click (instead of onClick) as Jason suggests as well.
Something like:
HTML
<tr ng-repeat="client in clients" ng-click="showClient(client)">
<td><a ng-href="#/user/{{client.tagid}}">{{client.firstname}}</a></td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
Controller
$scope.showClient = function(client) {
$location.path('#/user/' + client.tagid);
};
And styling to make it show as an clickable element (wont work in IE7)
CSS
tr {
cursor: pointer;
}
// or
[ng-click] {
cursor: pointer;
}
I wrote a directive so that you can simply write:
<tr ng-repeat="client in clients" such-href="#/user/{{client.tagid}}">
The source:
app.directive('suchHref', ['$location', function ($location) {
return{
restrict: 'A',
link: function (scope, element, attr) {
element.attr('style', 'cursor:pointer');
element.on('click', function(){
$location.url(attr.suchHref)
scope.$apply();
});
}
}
}]);
I use my own Angular directive that automatically wraps every cell in the row with a link.
The advantages are:
You don't duplicate code.
There is a regular link in every cell so things like "Open in new tab" (middle button or CTRL+click) works as expected (in opposite of the ng-click version).
HTML usage:
<tr row-href="#/user/{{client.tagid}}">
<td>...</td>
<td>...</td>
</tr>
Directive code (in TypeSript):
export class RowHrefDirective implements ng.IDirective {
constructor(private $compile: ng.ICompileService) {
}
restrict = "A";
scope = {
rowHref: "#rowHref"
};
link = (scope: Scope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes): void => {
const cells = element.children("td[skip-href!='yes'],th[skip-href!='yes']");
cells.addClass("cell-link");
for (const cell of cells.toArray()) {
const link = jQuery(`<a ng-href="{{ rowHref }}"></a>`);
this.$compile(link)(scope);
jQuery(cell).prepend(link);
}
}
}
Required CSS code (to fill the whole cell with the link):
td.cell-link,
th.cell-link {
position: relative;
}
td.cell-link a,
th.cell-link a {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
This is a CSS and HTML issue, not specific to AngularJS. The only allowed child of a <tr> is a <td>, and so you need to wrap the content of each cell in an anchor. You also need to make the anchor a block element to make it the full height/width of its container:
<tr ng-repeat="client in clients">
<td>
<a style="display: block;" ng-href="#/user/{{client.tagid}}">
{{client.firstname}}
</a>
</td>
<td>
<a style="display: block;" ng-href="#/user/{{client.tagid}}">
{{client.lastname}}
</a>
</td>
<td>
<a style="display: block;" ng-href="#/user/{{client.tagid}}">
{{client.inumber}}
</a>
</td>
</tr>
<tr ng-repeat="client in clients" ng-href="#/user/{{client.tagid}}">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
This is with the referrence to the options provided which may work.
I think this binds the entire row with the each field in the row. but is not clickable. how to do that. i mean we should be able to click so that another view/module can be open.
As requested by #sfs, here’s the solution which we’re using for ui-sref (Angular 1.5; TypeScript code, apologies for any inconvenience).
Credits: The code is based on the awesome answer by Martin Volek:
import { IDirective, IDirectiveFactory, ICompileService, forEach, element } from 'angular';
export default class RowUiSrefDirective implements IDirective {
restrict = 'A';
scope = { rowUiSref: '#rowUiSref' };
constructor(private $compile: ICompileService) { }
link = (scope, elm, attrs) => {
if (elm[0].tagName !== 'TR') {
throw new Error('This directive should only be used in <tr> elements.');
}
forEach(elm.children(), (cell) => {
if (cell.attributes['skip-href'] && cell.attributes['skip-href'].value !== 'false') {
return;
}
cell.className += ' cell-link';
let link = element('<a ui-sref="{{rowUiSref}}"></a>');
this.$compile(link)(scope);
element(cell).prepend(link);
});
};
static factory(): IDirectiveFactory {
let directive = ($compile: ICompileService) => new RowUiSrefDirective($compile);
directive.$inject = ['$compile'];
return directive;
};
}
Directive initialization:
import { module } from 'angular';
import RowUiSrefDirective from './rowUiSref';
module('app').directive('rowUiSref', RowUiSrefDirective.factory());
Example usage:
<table>
<tr ng-repeat="item in itemController.items"
row-ui-sref="state.item({itemId: '{{item.id}}'})">
<td>{{item.name}}</td>
<td>{{item.label}}</td>
</tr>
</table>
An ugly solution would be to just have 1 table cell which contains the link, then within that add another table with a table row and the other cells. So it would look like;
<tr ng-repeat="client in clients">
<a ng-href="#/user/{{client.tagid}}">
<table>
<tr>
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
</table>
</a>
</tr>
I do not agree with using tables for layout!
However, you are using JavaScript and angularjs, so you would be just as good adding a click event to the table row which sends the user to the url via window.location e.g.
<tr ng-repeat="client in clients" ng-click="ChangeLocation([yoururl])">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
Then have a function within your $scope to handle this;
$scope.ChangeLocation = function(url){
window.location = url;
}
Try for this...
HTML --->
<ul ng-repeat ="item in itemList ">
<li><a data-ng-href="{{getUrl(item)}}">{{item.Name}}</a></li>
</ul>
JS --->
$scope.getUrl = function (item) {
return '/<give your path here>/' + item.ID;
};
I adapted Martin Volek's Typescript code to make an AngularJS 1.x directive:
app.directive('rowHref', function ($compile)
{
return {
restrict: 'A',
link: function (scope, element, attr)
{
scope.rowHref=attr.rowHref;
var cells = element.children("td");
angular.forEach(cells, function (cell)
{
$(cell).addClass("cell-link");
var newElem = angular.element('<a ng-href="{{ rowHref }}"></a>');
$compile(newElem)(scope);
$(cell).append(newElem);
});
}
}
});
Add his same HTML and CSS

Resources