The javascript onDrop event is not executing when an object is dropped into a drop zone. I've tried re-writing this in at least half a dozen ways with no luck and no error message either. I was looking around for reasons that would prevent the ondrop event from executing and found:
HTML5/Canvas onDrop event isn't firing?
and
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#droptargets
To the best of my knowledge, I've accomplished all three requirements to trigger an ondrop event. I implemented both the ondragenter and ondragover events which both contain event.preventDefault(); and return false;. I also have event.preventDefault(); in the ondrop event.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.lists = [{name: "A", list: ["A Object 1", "A Object 2", "A Object 3"]},
{name: "B", list: ["B Object 1", "B Object 2", "B Object 3"]}];
$scope.drag_index = null;
$scope.drag_obj = null;
});
var dragging = false;
function toggle_dz() {
$(".drop-it").toggle();
}
function get_gbls(cs) {
while (cs.$parent) {
cs = cs.$parent;
}
return cs;
}
app.directive('zoneIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('dragenter',function(event){
event.preventDefault();
console.log("Drag Enter!");
return false;
});
$(element).on('dragover',function(event){
event.preventDefault();
console.log("Drag Over!");
return false;
});
}
};
});
app.directive('dragIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('drag',function(event){
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = scope.$index;
get_gbls(scope).drag_obj = scope.obj;
if (!dragging) {
toggle_dz();
dragging = true;
}
});
$(element).on('drop',function(event){
event.preventDefault();
alert("DROPPED!");
});
$(element).on('dragend',function(event){
toggle_dz();
dragging = false;
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = null;
get_gbls(scope).drag_obj = null;
get_gbls(scope).$apply();
});
}
};
});
.zone-it {
height: 150px;
width: 90%;
background-color: #1B6269;
border: 10px dashed #4D3A44;
border-radius: 10px;
margin: 10px 5%;
padding: 15px;
font-size: 100px;
color: #4D3A44;
text-shadow: 0 0 10px black;
}
.zone-it span {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid" ng-app="myApp" ng-controller="myCtrl">
<h2>Angular Drag n Drop</h2>
<div class="col-xs-6" ng-repeat="list in lists">
<h3>{{list.name}}</h3>
<hr>
<div class="col-xs-12 drop-it zone-it" zone-it style="display: none;"><span class="text-center glyphicon glyphicon-download"></span></div>
<div class="drop-it container-it">
<div class="col-sm-6 col-md-4 col-lg-3" ng-repeat="obj in list.list">
<div class="thumbnail drag-it" draggable="true" drag-it style="cursor:pointer">
<div class="caption text-center">{{obj}}</div>
</div>
</div>
</div>
</div>
</div>
Here is a fiddle of my code: https://jsfiddle.net/Ashkeelun/2uLwd077/1/
So, I figured it out. The ondrop event belongs with the drop zone not the item being dragged.
https://jsfiddle.net/Ashkeelun/2uLwd077/4/
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.lists = [{name: "A", list: ["A Object 1", "A Object 2", "A Object 3"]},
{name: "B", list: ["B Object 1", "B Object 2", "B Object 3"]}];
$scope.drag_index = null;
$scope.drag_obj = null;
});
var dragging = false;
function toggle_dz() {
$(".drop-it").toggle();
}
function get_gbls(cs) {
while (cs.$parent) {
cs = cs.$parent;
}
return cs;
}
app.directive('zoneIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('dragenter',function(event){
event.preventDefault();
console.log("Drag Enter!");
return false;
});
$(element).on('dragover',function(event){
event.preventDefault();
console.log("Drag Over!");
return false;
});
$(element).on('drop',function(event){
event.preventDefault();
alert("DROPPED!");
});
}
};
});
app.directive('dragIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('drag',function(event){
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = scope.$index;
get_gbls(scope).drag_obj = scope.obj;
if (!dragging) {
toggle_dz();
dragging = true;
}
});
$(element).on('dragend',function(event){
toggle_dz();
dragging = false;
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = null;
get_gbls(scope).drag_obj = null;
get_gbls(scope).$apply();
});
}
};
});
.zone-it {
height: 150px;
width: 90%;
background-color: #1B6269;
border: 10px dashed #4D3A44;
border-radius: 10px;
margin: 10px 5%;
padding: 15px;
font-size: 100px;
color: #4D3A44;
text-shadow: 0 0 10px black;
}
.zone-it span {
display: block;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div class="container-fluid" ng-app="myApp" ng-controller="myCtrl">
<h2>Angular Drag n Drop</h2>
<div class="col-xs-6" ng-repeat="list in lists">
<h3>{{list.name}}</h3>
<hr>
<div class="col-xs-12 drop-it zone-it" zone-it style="display: none;"><span class="text-center glyphicon glyphicon-download"></span></div>
<div class="drop-it container-it">
<div class="col-sm-6 col-md-4 col-lg-3" ng-repeat="obj in list.list">
<div class="thumbnail drag-it" draggable="true" drag-it style="cursor:pointer">
<div class="caption text-center">{{obj}}</div>
</div>
</div>
</div>
</div>
Related
What is the right way to change md-virtual-repeat's scroll to watch events from an other scroll ?
I have tried some manual triggering
And i readed this question but it is not exactly i want.
So is there a way to select a scrool to virtual-repeat container ?
EDIT 2
I need to change scrollbar of virtual repeat with scrollbar of Body
Live example
(function() {
'use strict';
var app = angular.module('MyApp', ['ngMaterial', 'ngMessages']);
app.filter('to_trusted', ['$sce', function($sce) {
return function(text) {
return $sce.trustAsHtml(text);
};
}]);
app.controller('AppCtrl', function($timeout) {
this.itemSize = 529.39;
var DynamicItems = function() {
this.loadedPages = {};
this.numItems = 0;
this.PAGE_SIZE = 50;
this.fetchNumItems_();
};
DynamicItems.prototype.getItemAtIndex = function(index) {
var pageNumber = Math.floor(index / this.PAGE_SIZE);
var page = this.loadedPages[pageNumber];
if (page) {
return page[index % this.PAGE_SIZE];
} else if (page !== null) {
this.fetchPage_(pageNumber);
}
};
DynamicItems.prototype.getLength = function() {
return this.numItems;
};
DynamicItems.prototype.fetchPage_ = function(pageNumber) {
this.loadedPages[pageNumber] = null;
$timeout(angular.noop, 300).then(angular.bind(this, function() {
this.loadedPages[pageNumber] = [];
var pageOffset = pageNumber * this.PAGE_SIZE;
//console.log(pageNumber);
for (var i = pageOffset; i < pageOffset + this.PAGE_SIZE; i++) {
var obj = {};
obj.name = 'Ad ' + i;
obj.surname = 'Soyad ' + i;
obj.age = i;
obj.image = 'http://lorempixel.com/75/75/cats?' + i;
obj.list = [];
obj.clicked = false;
obj.status = "asd";
obj.html = '' + i + '---Lorem Ipsum, dizgi ve baskı endüstrisinde kullanılan mıgır metinlerdir. Lorem Ipsum, adı bilinmeyen bir matbaacının bir hurufat numune kitabı oluşturmak üzere bir yazı galerisini alarak karıştırdığı 1500 lerden beri endüstri standardı sahte metinler olarak kullanılmıştır. Beşyüz yıl boyunca varlığını sürdürmekle kalmamış, aynı zamanda pek değişmeden elektronik dizgiye de sıçramıştır. 1960 larda Lorem Ipsum pasajları da içeren Letraset yapraklarının yayınlanması ile ve yakın zamanda Aldus PageMaker gibi Lorem Ipsum sürümleri içeren masaüstü yayıncılık yazılımları ile popüler olmuştur.' + i;
for (var j = 0; j < 1000; j++) {
obj.list.push('http://lorempixel.com/75/75/city/?' + j);
}
this.loadedPages[pageNumber].push(obj);
}
//this.setItemNum(this.numItems + this.PAGE_SIZE);
}));
};
DynamicItems.prototype.fetchNumItems_ = function() {
$timeout(angular.noop, 300).then(angular.bind(this, function() {
//console.log("fetchNumItems_");
this.numItems = 10000;
}));
};
DynamicItems.prototype.setItemNum = function(number) {
this.numItems = number;
};
this.dynamicItems = new DynamicItems();
//console.log(this.dynamicItems);
});
}());
.virtualRepeatdemoDeferredLoading #vertical-container {
width: 100%;
}
.virtualRepeatdemoDeferredLoading .repeated-item {
border-bottom: 1px solid #ddd;
box-sizing: border-box;
padding-top: 10px;
}
.virtualRepeatdemoDeferredLoading md-content {
margin: 16px;
}
.virtualRepeatdemoDeferredLoading md-virtual-repeat-container {
border: solid 1px grey;
}
.virtualRepeatdemoDeferredLoading .md-virtual-repeat-container .md-virtual-repeat-offsetter div {
padding-left: 16px;
}
.virtualRepeatdemoHorizontalUsage #horizontal-container {
height: 100px;
width: 100%;
}
.virtualRepeatdemoHorizontalUsage .repeated-item {
border-right: 1px solid #ddd;
box-sizing: border-box;
display: inline-block;
height: 84px;
padding-top: 10px;
text-align: center;
width: 100px;
}
.virtualRepeatdemoHorizontalUsage md-content {
margin: 16px;
}
.virtualRepeatdemoHorizontalUsage md-virtual-repeat-container {
border: solid 1px grey;
}
<!DOCTYPE html>
<html class=''>
<head>
<meta charset='UTF-8'>
<meta name="robots" content="noindex">
<link rel="shortcut icon" type="image/x-icon" href="//production-assets.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" />
<link rel="mask-icon" type="" href="//production-assets.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" />
<link rel="canonical" href="http://codepen.io/anon/pen/OWXMXW" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
<link rel='stylesheet prefetch' href='https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.1/angular-material.css'>
<link rel='stylesheet prefetch' href='https://material.angularjs.org/1.1.1/docs.css'>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-route.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js'></script>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js'></script>
<script src='https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.1/angular-material.js'></script>
</head>
<body>
<h1> Virtual Repeat Test </h1>
<div ng-controller="AppCtrl as ctrl" ng-cloak="" flex layout-fill layout-padding class="virtualRepeatdemoDeferredLoading" ng-app="MyApp">
<md-content layout="column" flex layout-fill>
<md-virtual-repeat-container flex layout-fill md-auto-shrink="false" layout id="vertical-container">
<div md-virtual-repeat="item in ctrl.dynamicItems" id="repeat_item" md-on-demand="true" md-item-size="ctrl.itemSize" layout-fill>
<img ng-src="{{item.image}}" class="md-avatar" alt="{{item.name}}" />
<br> Adı : {{item.name}} <br> Soyadı : {{item.surname}} <br> Yaşı : {{item.age}} <br> is Clicked : {{ item.clicked }} <br> status : {{ item.status }}
<p ng-bind-html=" item.html | to_trusted "> </p>
<h5 ng-click="item.clicked = !item.clicked; item.status = item.status + item.status; "> List Items </h5>
<md-content ng-if="item.clicked == true" class="virtualRepeatdemoHorizontalUsage" layout="column">
<md-virtual-repeat-container id="horizontal-container" md-orient-horizontal="">
<div md-virtual-repeat="picture in item.list" class="repeated-item" flex="">
<img ng-src="{{ picture }}" class="md-avatar" alt="{{ picture }}" />
</div>
</md-virtual-repeat-container>
</md-content>
<br>
</div>
</md-virtual-repeat-container>
</md-content>
</div>
</body>
</html>
If I understand your question correctly, you just want to scroll the virtual repeater div using a scrollbar somewhere else on your page? One way to do that would be to create a directive that listens to scroll event of the div you want to use as the visible scrollbar and then just scroll the other div the same percentage.
Here is one such directive. Add it to the md-virtual-repeat-container and point it to the div you want to scroll it. The divs can even be different heights.
Update
I changed the directive to fall back to the body tag if an element wasn't specified.
app = angular.module('myApp', ['ngMaterial']);
app.controller("myController", function($scope) {
$scope.items = [];
for (var i = 0; i < 5000000; i++) {
$scope.items.push(i);
}
});
app.directive("scrollFrom", function($window, $document) {
return {
scope: {
elTarget: '#scrollFrom'
},
link: function(scope, element, attrs) {
var body = $document[0].body;
angular.element(scope.elTarget || $window).bind("scroll", function() {
var percentScrolled = scope.elTarget ?
this.scrollHeight > 0 ? this.scrollTop / (this.scrollHeight - element.height()) : 0 :
body.scrollHeight > 0 ? body.scrollTop / (body.scrollHeight - element.height()) : 0;
var trgt = angular.element(element).find('.md-virtual-repeat-scroller')[0];
trgt.scrollTop = trgt.scrollHeight * percentScrolled;
});
}
};
});
#vertical-container {
height: 292px;
width: 100%;
max-width: 400px;
position: fixed;
top: 10px;
}
#vertical-container .md-virtual-repeat-scroller {
overflow: hidden;
}
.repeated-item {
border-bottom: 1px solid #ddd;
box-sizing: border-box;
height: 40px;
padding-top: 10px;
}
md-virtual-repeat-container {
border: solid 4px grey;
}
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.4/angular-material.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-aria.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.4/angular-material.min.js"></script>
</head>
<body style="height: 5000000px">
<div ng-controller="myController">
<md-virtual-repeat-container id="vertical-container" scroll-from>
<div md-virtual-repeat="item in items" class="repeated-item" flex>
{{item}}
</div>
</md-virtual-repeat-container>
</div>
</body>
</html>
I have a array of objects where i have a property of date_time, and in this array i wish to get the lenght of dates_times objects that are sooner with my current date_time.
Ex:
[data:[{date: "2017-02-24 16:41:51"}, {date: ""2017-02-21 16:41:51"}...],
last_clicked: "2017-02-24 19:41:51"]
I wish to get the length of objecs on "data" array that haves a date_time sooner than "last_clicked".
Maybe you can try something like this:
let length = data.filter(function(d) {
return new Date(d.date) < new Date(last_clicked)
}).length;
You can use Angulars-orderBy-filter. I set up an example for you, just swap out where I have the id key for your data's date key.
function exampleController($scope, exampleFactory, $filter) {
$scope.list = [];
$scope.reverse = false;
$scope.changeSortOrder = function() {
$scope.reverse = !$scope.reverse;
};
function getList() {
exampleFactory
.getList()
.then(function(list) {
// $scope.list = list;
//alternatively you could filter here and change the sort order with the button if needed at all.
$scope.list = $filter('orderBy')(list, '-id'); //where this would be replaced by date(note: the '-' in front of id changes the sort order ASC/DESC)
//$scope.list = $filter('orderBy')(list, 'id', true); //where 3rd argument is wether order should be reversed
});
}
getList();
}
function exampleFactory($http) {
var root = 'http://jsonplaceholder.typicode.com';
function getList() {
return $http.get(root + '/comments')
.then(function(resp) {
return resp.data;
});
}
return {
getList: getList
};
}
angular
.module('app', [])
.controller('exampleController', exampleController)
.factory('exampleFactory', exampleFactory);
.container-fluid {
background-color: #1D1F20;
color: #fff;
font-size: 14px;
font-weight: bold;
button {
margin-top: 20%;
}
}
ul li {
list-style: none;
margin: 10px;
}
.child-padding>div {
padding: 2px;
}
.col-md-2 {
position: fixed;
button {
margin-bottom: 10%;
}
}
.btn-circle {
width: 30px;
height: 30px;
text-align: center;
padding: 6px 0;
font-size: 12px;
line-height: 1.428571429;
border-radius: 50%;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div class="container-fluid" ng-app="app">
<div class="container" ng-controller="exampleController">
<div class="row">
<div class="col-md-2 text-center">
<button class="btn btn-primary" type="button" ng-click="changeSortOrder()">Change Sort Order</button>
</div>
<div class="col-md-10 pull-right">
<ul class="ul">
<li ng-repeat="comment in list | orderBy: 'date': reverse track by $index">
<div class="child-padding">
<div>
<span ng-bind="comment.email"></span>
<span class="pull-right btn-info btn-circle" ng-bind="comment.id"></span>
</div>
<div ng-bind="comment.body"></div>
</div>
<div ng-bind="comment.name"></div>
</li>
</ul>
</div>
</div>
</div>
</div>
Use Date.parse to parse your date strings
DEMO JsFiddle
The following code will alert:
Sooner times: 1
var o = {
data:[
{date: "2017-02-24 16:41:51"},
{date: "2017-02-21 16:41:51"}
],
last_clicked: "2017-02-24 12:41:51"
};
function getSoonerLength(data, soonerThan) {
var count = 0;
for (var i = 0 ; i < data.length ; i++) {
var d = Date.parse(data[i].date);
var than = Date.parse(soonerThan);
if (d < than)
count++;
}
return count;
}
alert('Sooner times: ' + getSoonerLength(o.data, o.last_clicked))
This post looks like duplicate, but I think is not. Now you can click Show box and show red box, if you want close this box, click outside.
Question: How close this red box on click again Show box text except click outside. And how change css style after click e.g. change font-size Show box after click
var myApplication = angular.module('myApp', []);
myApplication.directive('hideLogin', function($document){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('click', function(e) {
e.stopPropagation();
});
$document.bind('click', function() {
scope.$apply(attr.hideLogin);
})
}
}
});
myApplication.controller('hideContainer',function ($scope){
$scope.openLogin = function(){
$scope.userLogin = true;
};
$scope.hideLoginContainer = function(){
$scope.userLogin = false;
};
});
body {
position:relative;
}
.loginBox {
z-index:10;
background:red;
width:100px;
height:80px;
padding:10px;
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<body ng-app="myApp" ng-controller="hideContainer">
Show box
<div hide-login="hideLoginContainer()" class="loginBox" ng-show="userLogin" style="display:none;">
</div>
</body>
To be able to hide the box on click on it, use $scope.userLogin = !$scope.userLogin condition.
To change it's css style, e.g. font-size, use ng-class. If userLogin variable is true, it will add fontSize class into it, changing it's font-size.
var myApplication = angular.module('myApp', []);
myApplication.directive('hideLogin', function($document) {
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('click', function(e) {
e.stopPropagation();
});
$document.bind('click', function() {
scope.$apply(attr.hideLogin);
})
}
}
});
myApplication.controller('hideContainer', function($scope) {
$scope.openLogin = function() {
$scope.userLogin = !$scope.userLogin;
};
$scope.hideLoginContainer = function() {
$scope.userLogin = false;
};
});
body {
position: relative;
}
.loginBox {
z-index: 10;
background: red;
width: 100px;
height: 80px;
padding: 10px;
position: absolute;
}
.fontSize {
font-size: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<body ng-app="myApp" ng-controller="hideContainer">
Show box
<div hide-login="hideLoginContainer()" class="loginBox" ng-show="userLogin" style="display:none;">
</div>
</body>
instead of using multiple $scope for achieve something like this you can use a single $scope variable, take look at code snippet.
var myApplication = angular.module('myApp', []);
myApplication.directive('hideLogin', function($document){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('click', function(e) {
e.stopPropagation();
});
$document.bind('click', function() {
scope.$apply(attr.hideLogin);
})
}
}
});
myApplication.controller('hideContainer',function ($scope){
$scope.userLogin = true;
$scope.hideLoginContainer = function(){
$scope.userLogin = true;
};
});
body
{
position:relative;
}
.loginBox
{
z-index:10;
background:red;
width:100px;
height:80px;
padding:10px;
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<body ng-app="myApp" ng-controller="hideContainer">
Show box
<div hide-login="hideLoginContainer()" class="loginBox" ng-show="!userLogin" style="display:none;">
</div>
</body>
You could rename openLogin() to toggleLogin() and change the function accordingly to
$scope.toggleLogin = function(){
$scope.userLogin != $scope.userLogin;
};
That will toggle the box when you click on the link.
For the CSS part, use ng-class to conditionaly sign a class to the element if userLogin ==true
<div ng-class="{'myConditionalClass':userLogin }"></div>
<div ng-controller = "MyController">
<ul class="items" >
<div ng-repeat="item in colors" ng-class="{active:isActive(item)}" ng-click="select(item); whattoshow=!whattoshow">
<li class="col-md-3 col-sm-3 col-lg-3 col-xs-3" >
<img class="img-responsive" ng-src="images/colors/{{item.number}}.jpg">
</li>
<div class="col-md-12 col-sm-12 col-lg-12 col-xs-12" ng-class="whattoshow && isActive(item) ? 'show' : 'hidden'}">
<h2>{{item.bio}}</h2>
</div>
</div>
</ul>
</div>
That is my HTML code, the controller uses a JSON file to go through the items, and if you click on an item you shall see the description of it. As I try to show in this poorly drawn picture (http://i.stack.imgur.com/FCvmd.png), I can make the item bio appear after the item's picture, but as every description corresponds to its own item picture it makes my display order to change. I want every items description show on click below his own row of items.
Here is my angular controller if needed.
var myApp = angular.module('ProjectAssembly', []);
myApp.controller('MyController', ['$scope', '$http', function($scope, $http) {
$http.get('data/color.json').success(function(data) {
$scope.colors = data;
});
$scope.select= function(item) {
$scope.selected = item;
};
$scope.isActive = function(item) {
return $scope.selected === item;
};
}]);
I hope you can help my case, it seemed to be easy, but I can't find the solution :/
What you need is ng-repeat-start and ng-repeat-end and split your data into rows.
See details in example:
var myApp = angular.module('ProjectAssembly', []);
myApp.controller('MyController', ['$scope', '$http',
function($scope, $http) {
//$http.get('data/color.json').success(function(data) {});
$scope.colors = [{
number: 1,
bio: '1111111111111111111111111111111111111111'
}, {
number: 2,
bio: '2222222222222222222222222222222222222222'
}, {
number: 3,
bio: '33333333333333333333333333333333333333333'
}, {
number: 4,
bio: '4444444444444444444444444444444444444444'
}, {
number: 5,
bio: '55555555555555555555555555555'
}]
$scope.colors = (function(data) {
var result = [];
angular.forEach(data, function(val, index) {
var key = Math.floor(index / 4);
if (!result[key]) {
result[key] = [];
}
result[key].push(val);
});
return result;
})($scope.colors);
$scope.select = function(item, rowIndex, columnIndex) {
if (item == $scope.selected) {
$scope.selected = null;
$scope.selectedRowIndex = null;
$scope.selectedColumnIndex = null;
return false;
}
$scope.selected = item;
$scope.selectedRowIndex = rowIndex;
$scope.selectedColumnIndex = columnIndex;
};
$scope.isActive = function(item) {
return $scope.selected === item;
};
}
]);
.item-tr {
border: 1px solid #555;
margin-top: 5px;
position: relative;
background: #555;
}
.item-tr:before {
content: ' ';
position: absolute;
border-top: 5px solid transparent;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid #555;
top: -11px;
}
.item-tr-0:before {
left: 12.5%;
}
.item-tr-1:before {
left: 37.5%;
}
.item-tr-2:before {
left: 62.5%;
}
.item-tr-3:before {
left: 87.5%;
}
.item-td {
border: 1px solid #555;
}
<link href="//cdn.bootcss.com/bootstrap/3.0.0/css/bootstrap-theme.css" rel="stylesheet">
<link href="//cdn.bootcss.com/bootstrap/3.0.0/css/bootstrap.css" rel="stylesheet">
<script src="//cdn.bootcss.com/jquery/2.2.1/jquery.js"></script>
<script src="//cdn.bootcss.com/bootstrap/3.0.0/js/bootstrap.js"></script>
<script src="//cdn.bootcss.com/angular.js/1.4.7/angular.js"></script>
<div ng-app="ProjectAssembly">
<div ng-controller="MyController">
<ul class="items">
<li ng-repeat-start="row in colors track by $index" class="row">
<div class="col-md-3 col-sm-3 col-lg-3 col-xs-3 item-td" ng-repeat="item in row" ng-class="{active:isActive(item)}" ng-click="select(item,$parent.$index,$index); whattoshow=!whattoshow">
<span>
<img class="img-responsive" ng-src="images/colors/{{item.number}}.jpg">
{{item.number}}
</span>
</div>
</li>
<li ng-repeat-end ng-show="selected && selectedRowIndex==$index" class="row item-tr item-tr-{{selectedColumnIndex}}">
<div>
<h2>{{selected.bio}}</h2>
</div>
</li>
</ul>
</div>
</div>
My app is in this Fiddle
I need to render a star rating system dynamically from a http service, where the current stars and maximum stars can vary with each case.
Is it a good idea to create arrays from $scope.current and
$scope.max - $scope.current and pass them and run ng-repeat over them, or there is a more optimised solution than this.
Iteration ng-repeat only X times in AngularJs
Star Rating can be done either statically (read-only) or dynamically
If you want just simply to display Rating as star then try the below one
Static Star Rating
Working Example
html
<body ng-app="starApp">
<div ng-controller="StarCtrl"> <span ng-repeat="rating in ratings">{{rating.current}} out of
{{rating.max}}
<div star-rating rating-value="rating.current" max="rating.max" ></div>
</span>
</div>
</body>
script
var starApp = angular.module('starApp', []);
starApp.controller('StarCtrl', ['$scope', function ($scope) {
$scope.ratings = [{
current: 5,
max: 10
}, {
current: 3,
max: 5
}];
}]);
starApp.directive('starRating', function () {
return {
restrict: 'A',
template: '<ul class="rating">' +
'<li ng-repeat="star in stars" ng-class="star">' +
'\u2605' +
'</li>' +
'</ul>',
scope: {
ratingValue: '=',
max: '='
},
link: function (scope, elem, attrs) {
scope.stars = [];
for (var i = 0; i < scope.max; i++) {
scope.stars.push({
filled: i < scope.ratingValue
});
}
}
}
});
If you want to do Star Rating dynamically try this out
Dynamic Star Rating
Working Demo
Html
<body ng-app="starApp">
<div ng-controller="StarCtrl"> <span ng-repeat="rating in ratings">{{rating.current}} out of
{{rating.max}}
<div star-rating rating-value="rating.current" max="rating.max" on-rating-selected="getSelectedRating(rating)"></div>
</span>
</div>
</body>
script
var starApp = angular.module('starApp', []);
starApp.controller('StarCtrl', ['$scope', function ($scope) {
$scope.rating = 0;
$scope.ratings = [{
current: 5,
max: 10
}, {
current: 3,
max: 5
}];
$scope.getSelectedRating = function (rating) {
console.log(rating);
}
}]);
starApp.directive('starRating', function () {
return {
restrict: 'A',
template: '<ul class="rating">' +
'<li ng-repeat="star in stars" ng-class="star" ng-click="toggle($index)">' +
'\u2605' +
'</li>' +
'</ul>',
scope: {
ratingValue: '=',
max: '=',
onRatingSelected: '&'
},
link: function (scope, elem, attrs) {
var updateStars = function () {
scope.stars = [];
for (var i = 0; i < scope.max; i++) {
scope.stars.push({
filled: i < scope.ratingValue
});
}
};
scope.toggle = function (index) {
scope.ratingValue = index + 1;
scope.onRatingSelected({
rating: index + 1
});
};
scope.$watch('ratingValue', function (oldVal, newVal) {
if (newVal) {
updateStars();
}
});
}
}
});
There is a wonderful tutorial here for more explanation about Angular Star Rating
You can even try angular-ui. Here is the link.
Just need to add this tag.
<rating ng-model="rate" max="max"
readonly="isReadonly"
on-hover="hoveringOver(value)"
on-leave="overStar = null">
//Controller
var starApp = angular.module('starApp', []);
starApp.controller('StarCtrl', ['$scope', function ($scope) {
$scope.maxRating = 10;
$scope.ratedBy = 0;
$scope.rateBy = function (star) {
$scope.ratedBy = star;
}
}]);
.rating {
color: #a9a9a9;
margin: 0;
padding: 0;
}
ul.rating {
display: inline-block;
}
.rating li {
list-style-type: none;
display: inline-block;
padding: 1px;
text-align: center;
font-weight: bold;
cursor: pointer;
}
.rating .filled {
color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="starApp">
<div ng-controller="StarCtrl">
<ul class="rating">
<li ng-repeat="n in [].constructor(maxRating) track by $index">
<span ng-click="rateBy($index+1)" ng-show="ratedBy > $index" class="filled">★</span>
<span ng-click="rateBy($index+1)" ng-show="ratedBy <= $index">★</span>
</li>
</ul>
</div>
</body>
You could hold an array of objects like so:
var starApp = angular.module('starApp',[]);
starApp.controller ('StarCtrl', ['$scope', function ($scope) {
$scope.ratings = [];
var rating = {
current : 5,
max : 10
}
$scope.ratings.push(rating); // instead you would push what your http service returns into thearray.
}]);
Then in your view you could use ng-repeat like so:
<body ng-app="starApp">
<div ng-controller="StarCtrl">
<span ng-repeat="rating in ratings">{{rating.current}} out of {{rating.max}}</span>
</div>
</body>
My minimalistic approach:
The view
<head>
<!-- alternatively you may use another CSS library (like FontAwesome) to represent the star glyphs -->
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"></link>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0-rc.2/angular.min.js"></script>
<!-- insert the JavaScript controller and the CSS enhancements here -->
</head>
<body>
<div ng-app="StarRatings">
<div ng-controller="myController as ctrl">
<div ng-repeat="n in ctrl.getStarArray()" ng-class="ctrl.getClass(n)" ng-mouseover="ctrl.setClass($event,n)"> </div>
<p>
You have chosen {{ctrl.selStars}} stars
</p>
</div>
</div>
</body>
Note: if you want to use the onClick event instead onMouseOver event then replace ng-mouseover with ng-click in the HTML above.
The controller
<script>
(function() {
var app = angular.module('StarRatings', []);
app.controller('myController', function() {
this.selStars = 0; // initial stars count
this.maxStars = 5; // maximum number of stars
// a helper function used within view
this.getStarArray = function() {
var result = [];
for (var i = 1; i <= this.maxStars; i++)
result.push(i);
return result;
};
// the class used to paint a star (filled/empty) by its position
this.getClass = function(index) {
return 'glyphicon glyphicon-star' + (this.selStars >= index ? '' : '-empty');
};
// set the DOM element class (filled/empty star)
this.setClass = function(sender, index) {
this.selStars = index;
sender.currentTarget.setAttribute('class', this.getClass(index));
};
});
})();
</script>
Optionally some CSS enhancements
<style>
.glyphicon {
color: gold;
cursor: pointer;
font-size: 1.25em;
}
</style>
Not convinced? Try this JSFiddle: https://jsfiddle.net/h4zo730f/2/
let app = angular.module ('myapp',[])
-
##star Rating Styles
----------------------*/
.stars {
padding-top: 10px;
width: 100%;
display: inline-block;
}
span.glyphicon {
padding: 5px;
}
.glyphicon-star-empty {
color: #9d9d9d;
}
.glyphicon-star-empty,
.glyphicon-star {
font-size: 18px;
}
.glyphicon-star {
color: #FD4;
transition: all .25s;
}
.glyphicon-star:hover {
transform: rotate(-15deg) scale(1.3);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div ng-app= "myapp" >
<div class="stars">
<div id="stars" class="star">
<span ng-repeat="x in [0,1,2,3,4,5]" ng-if="($index < 4)" class="glyphicon glyphicon-star"> </span>
<span ng-repeat="x in [0,1,2,3,4,5]" ng-if="($index >= 4 && $index < 5) " class="glyphicon glyphicon-star-empty"></span>
</div>
</div>
</div>
hmc.starRating.js
angular.module('starRatings',[]).directive('starRating', function () {
return {
restrict: 'A',
template: '<ul class="rating">' +
'<li ng-repeat="star in stars" ng-class="star">' +
'\u2605' +
'</li>' +
'</ul>',
scope: {
ratingValue: '=',
max: '='
},
link: function (scope, elem, attrs) {
console.log(scope.ratingValue);
function buildStars(){
scope.stars = [];
for (var i = 0; i < scope.max; i++) {
scope.stars.push({
filled: i < scope.ratingValue
});
}
}
buildStars();
scope.$watch('ratingValue',function(oldVal, newVal){
if(oldVal !== newVal){
buildStars();
}
})
}
}
});
<script src="hmc.starRating.js"></script>
**app.js**
var app = angular.module('app', ['ui.bootstrap', 'starRatings']);
**indix.html**
<div star-rating rating-value="7" max="8" ></div>
.rating {
color: #a9a9a9;
margin: 0 !important;
padding: 0 !important;
}
ul.rating {
display: inline-block !important;
}
.rating li {
list-style-type: none !important;
display: inline-block !important;
padding: 1px !important;
text-align: center !important;
font-weight: bold !important;
cursor: pointer !important;
width: 13px !important;
color: #ccc !important;
font-size: 16px !important;
}
.rating .filled {
color: #ff6131 !important;
width: 13px !important;
}