AngularJS binding issues - angularjs

When I do the following in my code
<pre>{{uploader.queue.indexOf(item)|json}}</pre>
I get an index of the element that I am looking for but if I do something like this
removeAllFiles(uploader.queue.indexOf(item))
The result is always
-1

Try this out
Working Demo
html
<div class="container" ng-app="main" ng-controller="Controller">
<div ng-repeat="uploader in uploaders">
<button ng-click="removeAllFiles(uploader.queue.indexOf(item))">{{uploader.queue.indexOf(item)|json}}
</button>
</div>
</div>
script
angular.module('main', []);
// Main Controller
function Controller($scope) {
$scope.item = 'N';
$scope.uploaders = [{
clickable: true,
id:1,
queue: "ABC-Name"
}, {
clickable: false,
id:2,
queue: "XYZ-Name"
}, {
clickable: true,
id:3,
queue: "LMN-Name"
}];
$scope.removeAllFiles = function(item) {
console.log(item);
}
}

Related

Controlling ng-repeat iterations

HTML :
<div ng-repeat="data in $ctrl.list">
<div ng-init="$ctrl.applyAction(data)">
<h4>{{data.name}}</h4>
<ul ng-if="data.steps">
<li ng-repeat="step in data.steps">{{step.name}}</li>
</ul>
</div>
</div>
Controller :
$onInit() {
this.list = [{
name: "First Obj"
}, {
name: "Second Obj"
}, {
name: "Third Obj"
}, {
name: "Fourth Obj"
}];
}
applyAction(data) {
this.someHttpService.getResponse(data).then(function(success) {
data.reqForSecondServiceCall = success.data;
this.secondServiceCall(data);
}, function(error) {
// console.log(error);
});
}
secondServiceCall(data) {
this.someHttpService.getSecondServiceResponse(data).then(function(success) {
data.status = success.data;
}, function(error) {
// console.log(error);
});
}
Currently ng-repeat will be iterating through the list object irrespective of the service calls made on each object (asynchronous).
And the desired functionality is to render the current object only when the applyActions method is completed on previous object.
One solution is to queue the calls in an event queue and then invoke the events one by one when previous call is completed
angular.module('myApp',[]).controller('myCtrl', function($scope, $http, $timeout){
$scope.title = 'welcome';
$scope.finishedEvent = '';
$scope.eventQueue = [];
$scope.list = [{
name: "First Obj"
}, {
name: "Second Obj"
}, {
name: "Third Obj"
}, {
name: "Fourth Obj"
}];
$scope.applyAction = function(data, index) {
//declare the event
var event = function(){
var testApi = "https://jsonplaceholder.typicode.com/posts";
$http.get(testApi).then(function(response) {
data.steps = response.data.slice(0,2);
$scope.finishedEvent = data.name;
}, function(error) {
console.log(error);
});
};
if(index == 0){
event();
}else{
$scope.eventQueue.push(event);
}
};
$scope.$watch('finishedEvent', function(){
if($scope.eventQueue.length > 0){
$timeout(function(){
console.log($scope.finishedEvent + '- loaded')
var event = $scope.eventQueue[0];
$scope.eventQueue.splice(0, 1); //remove current event from queue
event();
}, 1000);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<h1>{{title}}</h1>
<div ng-repeat="data in list">
<div ng-init="applyAction(data, $index)">
<h4>{{data.name}}</h4>
<ul ng-if="data.steps">
<li ng-repeat="step in data.steps">{{step.title}}</li>
</ul>
</div>
</div>
</body>
NOTE 1: I used a dummie api just to have live data
NOTE 2: Remove the $timeout, only added it to make the example clear
Here's a plunker with the example

Can't get RubaXa/angular-legacy-sortablejs to move items between lists

Can someone tell me why this plunk will not allow me to move items between the two lists?
I am able to get shared lists to work using the plain RubaXa Sortable library and plain Javascript, but I have not been able to get them to work with Angular and RubaXa/angular-legacy-sortablejs library.
I have read and re-read the docs on the configuration options here and I swear I am doing it correctly.
I have also reviewed the example from the docs (not allowed to link it here due to low rep points) with no success.
I have created two lists and connected them using identical config info:
var ctrl = this;
ctrl.sortableConf = {
group: {
name: 'tags',
pull: true,
put: true
},
sort: true,
animation: 150,
draggable: '.list-group-item',
filter: '.js-remove',
chosenClass: ".sortable-chosen"
};
They both sort just fine internally, I just can't drag an item from one to the other or vice versa.
The documentation is wrong, or I don't know how to properly reference it when not using a partial page instead of an embedded template.
After debugging the options-loading code in sortable.js, I realized that it was not loading the group: block from the ctrl.sortableConf and I was getting stuck with the default values:
After trying a ton of different ways to do this, I stumbled on this example and was able to work it out form there.
Here is a plunk and a copy of the code just in case that goes away:
// create angular app
var tagsApp = angular.module('tagsApp', ['ng-sortable']);
tagsApp.controller('bugTagController', ['$scope', function($scope) {
$scope.tags = [
'Beans',
'Potatoes'
];
$scope.bugTagControllerConfig = {
group: 'tags',
pull: true,
put: true,
sort: true,
animation: 150,
draggable: '.list-group-item',
filter: '.js-remove',
chosenClass: ".sortable-chosen",
accept: function(sourceItemHandleScope, destSortableScope) {
console.log('masterTagController:accept');
return true;
},
onStart: function(evt) {
console.log('masterTagController:onStart');
},
onEnd: function(evt) {
console.log('masterTagController:onEnd');
},
onAdd: function(evt) {
console.log('masterTagController:onAdd');
},
onRemove: function(evt) {
console.log('masterTagController:onAdd');
},
onFilter: function(evt) {
var el = masterTags.closest(evt.item); // get dragged item
el && el.parentNode.removeChild(el);
console.log('masterTagController:onFilter');
},
onSort: function(evt) {
console.log('masterTagController:onSort');
var $item = $(evt.item);
var id = $item.data('id');
if (evt.action === 'add') {
console.log('masterTagController:add');
// put a check to make sure it's unique
// check to see if this node has already been added and prevent it it has
var itemCount = evt.item.parentNode.children.length;
for (var i = 0; i < itemCount; i++) {
var $child = $(evt.item.parentNode.children[i]);
var childId = $child.data('id');
if (childId === id && i !== evt.newIndex) {
console.log('masterTagController:rejectedNewItem');
evt.preventDefault();
return;
}
}
if (evt.newIndex === itemCount - 1) {
Sortable.utils.swap(evt.item.parentNode, evt.newIndex, evt.newIndex - 1);
}
}
}
};
}]);
tagsApp.controller('masterTagController', ['$scope', function($scope) {
$scope.tags = [
'Apples',
'Oranges',
'Comquats',
'Bannanas',
'Pineapples'
];
$scope.masterTagControllerConfig = {
group: 'tags',
pull: true,
put: true,
sort: true,
animation: 150,
draggable: '.list-group-item',
filter: '.js-remove',
chosenClass: ".sortable-chosen",
accept: function(sourceItemHandleScope, destSortableScope) {
console.log('masterTagController:accept');
return true
},
onStart: function(evt) {
console.log('masterTagController:onStart');
},
onEnd: function(evt) {
console.log('masterTagController:onEnd');
},
onAdd: function(evt) {
console.log('masterTagController:onAdd');
},
onRemove: function(evt) {
console.log('masterTagController:onAdd');
},
onFilter: function(evt) {
var el = masterTags.closest(evt.item); // get dragged item
el && el.parentNode.removeChild(el);
console.log('masterTagController:onFilter');
},
onSort: function(evt) {
console.log('masterTagController:onSort');
var $item = $(evt.item);
var id = $item.data('id');
if (evt.action === 'add') {
console.log('masterTagController:add');
// put a check to make sure it's unique
// check to see if this node has already been added and prevent it it has
var itemCount = evt.item.parentNode.children.length;
for (var i = 0; i < itemCount; i++) {
var $child = $(evt.item.parentNode.children[i]);
var childId = $child.data('id');
if (childId === id && i !== evt.newIndex) {
console.log('masterTagController:rejectedNewItem');
evt.preventDefault();
return;
}
}
if (evt.newIndex === itemCount - 1) {
Sortable.utils.swap(evt.item.parentNode, evt.newIndex, evt.newIndex - 1);
}
}
}
};
}]);
And here is the html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div ng-app="tagsApp">
<!-- Starting Secondary Tags -->
<div class="col-md-2">
<h2>Tags on this list</h2>
<div class="well" ng-controller="bugTagController">
<ul id="bugTags" class="list-group" ng-sortable="bugTagControllerConfig" ng-model="tags" style="well-lg">
<li class="list-group-item" ng-repeat="tag in tags" ng-sortable-item style="well-lg">
<div ng-sortable-item-handle>{{ tag }}</div>
</li>
</ul>
</div>
</div>
<!-- Ending Secondary Tags -->
<!-- Starting Master Tags -->
<div class="col-md-2">
<h2>Master Tag List</h2>
<div class="well" ng-controller="masterTagController">
<ul id="masterTags" class="list-group" ng-sortable="masterTagControllerConfig" ng-model="tags" style="well-lg">
<li class="list-group-item" ng-repeat="tag in tags" ng-sortable-item style="well-lg">
<div ng-sortable-item-handle>{{ tag }}</div>
</li>
</ul>
</div>
<!-- Ending Master Tags -->
</div>
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.0.js" integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular-route.js"></script>
<script type="text/javascript" src="https://rubaxa.github.io/Sortable/Sortable.js"></script>
<script type="text/javascript" src="ng-sortable.js"></script>
<script src="script.js"></script>
</body>
</html>

Polymer neon-animation: Element is remains visible after animating

I downloaded the Polymer Starter Kit and am trying to animate an paper-element like so
<section data-route="contact">
<button on-click="_onButtonClick">Toggle</button>
<my-dialog>
<paper-material elevation="1">
<h2 class="page-title">Contact</h2>
<p>This is the contact section</p>
</paper-material>
</my-dialog>
</section>
my-dialog.html as follows:
<dom-module id="my-dialog">
<template>
<content></content>
</template>
</dom-module>
<script>
Polymer({
is: 'my-dialog',
behaviors: [
Polymer.NeonAnimationRunnerBehavior
],
properties: {
opened: {
type: Boolean
},
animationConfig: {
type: Object,
value: function() {
return {
'entry': [{
name: 'slide-left-animation',
node: this
}],
'exit': [{
name: 'fade-out-animation',
node: this
}]
}
}
}
},
listeners: {
'neon-animation-finish': '_onAnimationFinish'
},
_onAnimationFinish: function() {
if (!this.opened) {
this.style.display = '';
}
},
show: function() {
this.opened = true;
this.style.display = 'inline-block';
this.playAnimation('entry');
},
hide: function() {
this.opened = false;
this.playAnimation('exit');
}
});
</script>
The problem I'm facing is that after toggling the animation, my paper-element is squished and remains visible on screen. How do I make it not visible after animation? I've tried hardcoding <paper-material hidden?=true> but that also does not hide the element.
As commented, you simply need to change this.style.display = 'none';

Angular Slick autoplaySpeed isn't working

I'm using 'Angular Slick' to make a carousel, everthings working as I wanted, except for 'autoplaySpeed' property, when I use it, it is not working, in the docs there is nothing related to...
HTML:
<slick init-onload="false" slick-apply='slickApply' autoplaySpeed="3000" data="dataLoaded" autoplay="true" slides-to-show="1" dots="true">
<div ng-repeat="item in carouselItems">
<h2 class="starter-benefits__title">{{item.title | translate}}</h2>
<h6 class="starter-benefits__info">{{item.message | translate}}</h6>
</div>
</slick>
JS.
angular.module('app')
.controller('initCtrl', function($scope, $timeout) {
$scope.carouselItems = [];
$timeout(function() {
$scope.carouselItems = [
{
title: 'LABEL_INIT_CAROUSEL_FIRST_TITLE',
message: 'LABEL_INIT_CAROUSEL_FIRST_MESSAGE'
},
{
title: 'LABEL_INIT_CAROUSEL_SECOND_TITLE',
message: 'LABEL_INIT_CAROUSEL_SECOND_MESSAGE'
},
{
title: 'LABEL_INIT_CAROUSEL_THIRD_TITLE',
message: 'LABEL_INIT_CAROUSEL_THIRD_MESSAGE'
},
{
title: 'LABEL_INIT_CAROUSEL_FOURTH_TITLE',
message: 'LABEL_INIT_CAROUSEL_FOURTH_MESSAGE'
}
];
$scope.dataLoaded = true;
}, 2000);
});
Hope guys can help me figure out what's going on.
Thank you.

Angular Directive in ng-repeat generating randomly uncorrect DOM

Hello i have a directive like this in my ASP MVC application + Kendo Upload (doesn't matter)
<div ng-repeat="dp in dealerphotos" class="imgbox">
<div ng-if="dp.DealerPhotoId != 0">
<div class="img-wrapper">
<a data-lightbox="{{ dp.DealerId }}{{ dp.PhotoId }}{{ dp.FileName }}" data-title="{{ dp.FileName }}" href="~/Upload/{{ dp.DealerId }}/{{ dp.PhotoId }}/{{ dp.FileName }}">
<img ng-src="~/Image/Resized?size={{ resize }}&dealerId={{ dp.DealerId }}&photoId={{ dp.PhotoId }}&fileName={{ dp.FileName }}" alt="" class="uploaded" center-preview />
</a>
</div>
<div class="btnblock">
<button ng-click="changePhoto(dp.DealerPhotoId, dp.PhotoId, $index)" title="#Resources.Strings.ButtonChange"><span class="icon pencil"></span></button>
<button ng-click="removePhoto(dp.DealerPhotoId)" title="#Resources.Strings.ButtonRemove"><span class="icon trash"></span></button>
</div>
</div>
<div ng-show="dp.DealerPhotoId == 0" ng-attr-class="{{ (dp.IsFirstMandatory || dp.IsFirstMandatoryIfInstalled) ? 'mandatory' : '' }}">
<input name="files"
type="file"
kendo-upload
k-multiple="false"
k-async="{ saveUrl: '/Steps/Save', autoUpload: true }"
k-select="onSelect"
k-error="onError"
k-success="onSuccess"
k-upload="onUpload"
title="#Resources.Strings.ButtonAdd" />
<div class="mandatory-marker">
<p ng-if="dp.IsFirstMandatory">#Resources.Strings.StepMandatory</p>
<p ng-if="!dp.IsFirstMandatory && dp.IsFirstMandatoryIfInstalled" class="installed">#Resources.Strings.StepMandatoryIfInstalled</p>
</div>
</div>
</div>
With .js code:
//IFFE
(function () {
var app = angular.module("app");
app.directive('tripleUploadDirective', ['$http', function () {
var controller = [
'$scope', '$http', function ($scope, $http) {
$scope.dealerPhotoId = null;
$scope.removePhoto = function (id) {
swal({
title: "", text: localization.StepRemoveConfirm, type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: localization.AlertYesRemove,
closeOnConfirm: true,
animation: "slide-from-top"
}, function () {
$http.post("/Steps/Remove", { dealerPhotoId: id }).then(function (data) {
for (var i = 0; i < data.data.length; i++) {
if (i == 0 && data.data[i].DealerPhotoId == 0) {
if ($scope.mandatory)
data.data[i].IsFirstMandatory = true;
if ($scope.mandatoryifinstalled)
data.data[i].IsFirstMandatoryIfInstalled = true;
}
}
$scope.dealerphotos = data.data;
});
});
};
$scope.changePhoto = function (dealerPhotoId, id, index) {
swal({
title: "", text: localization.StepChangeConfirm, type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: localization.AlertYesChange,
closeOnConfirm: true,
animation: "slide-from-top"
}, function () {
$scope.dealerPhotoId = dealerPhotoId;
var uploadinput = angular.element("#div_" + id + " input[name=files]")[index];
angular.element(uploadinput).click();
});
};
$scope.onSelect = function (e) {
$.each(e.files, function (index, value) {
var ok = value.extension.toLowerCase() == ".jpg" || value.extension == ".jpeg";
if (!ok) {
e.preventDefault();
swal({ title: "", text: localization.StepValidateExtension, type: "error", confirmButtonText: localization.AlertOK, animation: "slide-from-top" });
}
});
};
$scope.onError = function (e) {
swal({ title: "", text: e.XMLHttpRequest.response, type: "error", confirmButtonText: localization.AlertOK, animation: "slide-from-top" });
$scope.$apply();
};
$scope.onSuccess = function (e) {
if (e.response != null) {
for (var i = 0; i < e.response.length; i++) {
if (i == 0 && e.response[i].DealerPhotoId == 0) {
if ($scope.mandatory)
e.response[i].IsFirstMandatory = true;
if ($scope.mandatoryifinstalled)
e.response[i].IsFirstMandatoryIfInstalled = true;
}
}
$scope.dealerphotos = e.response;
$scope.$apply();
}
};
$scope.onUpload = function (e) {
e.data = { photoId: $scope.photoid, dealerPhotoId: $scope.dealerPhotoId };
$scope.dealerPhotoId = null;
};
}];
return {
restrict: 'EAC',
scope: {
dealerphotos: '=dealerphotos',
photoid: '=photoid',
mandatory: '=mandatory',
mandatoryifinstalled: '=mandatoryifinstalled',
resize: '=resize'
},
replace: true,
templateUrl: '/Directives/TripleUpload',
controller: controller
};
}]);
})();
This directive is used in ng-repeat:
<div ng-repeat="step in matrixCtrl.allSteps" class="m-step">
<div class="step-title">{{step.stepIndex}} | {{ step.Name }}</div>
<div triple-upload-directive dealerphotos="step.dealerPhotos" photoid="step.PhotoId" resize="170" mandatory="step.IsMandatory" mandatoryifinstalled="step.IsMandatoryIfInstalled" class="img-uploder {{ step.IsMandatory ? 'mandatory' : '' }}"></div>
</div>
I am setting allSteps in matrixCtrl in success() callback of $http.get().
My problem is the very strange behaviour of ng-repeat.. sometimes (very randomly), my DOM is not generated correctly. (all directives are rendered only in last ng-repeat iteration), in other iterations there are only titles.
Incorrect rendering image:

Resources