Problem: My json object is updating, but the slider does not update for all resorts. It should be updating as the json object changes but sometimes does not.
For the resorts (image collections) that do not update, it gives me an error: "cannot read property 'element' of undefined and breaks on angular-flexslider.js line 104. I cannot find any relation with the resorts that are giving me this error vs the ones that do not.
Summary of my script: I'm using angular-flexslider with a slider sync. I have a service that grabs image data and sends it to the controller. The controller picks it up and runs reorganize(), which takes the object it is given and reformats it into an array that flexslider supports.
This object needs to be updated as the images are updated. I have a dropdown that allows users to change the resort and I want the slider to reflect those changes.
Here is my code
JS:
resortModule.controller('galleryController', ['$scope', 'locaService', function($scope, locaService) {
//object to receive images
$scope.images;
//object used for image slider
$scope.imagePaths = [];
//variable that gives me resort ID
$scope.resort;
//restructures images array to work better with image slider
$scope.reorganize= function(){
$scope.imagePaths.length= 0;
for(var i = 0; i < $scope.images.length; i++) {
var obj= {custom: "assets/images/resorts/" + $scope.images[i].resort + "/gallery/" + $scope.images[i].file_name, thumbnail:"assets/images/resorts/" + $scope.images[i].resort + "/thumbnail/" + $scope.images[i].file_name}
$scope.imagePaths.push(obj);
}
}
//watches factory for updates to objects/ variables
$scope.$on('imagesUpdated', function() {
$scope.images = locaService.images;
$scope.reorganize();
});
$scope.$on('resortUpdated', function() {
$scope.resort = locaService.resort;
});
}]);
HTML:
<flex-slider slider-id="slider" flex-slide="image in imagePaths track by $index" animation="fade" animation-loop="false" sync="#carousel" slideshow="false" control-nav="false" prev-text="" next-text="" init-delay="100">
<li>
<img ng-src="{{image.custom}}" alt="Luxury Resort Rental Image">
</li>
</flex-slider>
<flex-slider class="slides hide-tablet-down" slider-id="carousel" flex-slide="image in imagePaths track by $index" animation="slide" animation-loop="false" item-width="210" item-margin="5" as-nav-for="#slider" slideshow="false" prev-text="" next-text="" control-nav="false">
<li>
<img ng-src="{{image.thumbnail}}" alt="Luxury Resort Rental Image">
</li>
</flex-slider>
Does anyone have any insight on this error? Or what I might be doing wrong? I've been researching it all day but have only found this:
https://github.com/thenikso/angular-flexslider/issues/53
and this:
https://github.com/thenikso/angular-flexslider/pull/63
Which did nothing for me, but I might not have understood them entirely. I'm not a seasoned angular developer and I'm learning as I go along. Thanks in advance for your help.
I commented out the following lines in the angular-flexslider.js and it seemed to fix the problem. Let me know if you have a better solution:
if ((toAdd.length === 1 && toRemove.length === 0) || toAdd.length === 0) {
...
return $scope.$evalAsync(function() { return slider.addSlide(item.element, idx); }); }); } return; }`
Related
I'm having some difficulty getting items to display inside this grid when getting them from Firebase. I managed to get it working with a custom Service that returned a static array.
I know the data is reaching the browser because I can log it out as JSON like so.
<pre>
{{ data | json }}
</pre>
HTML
<ul class="dynamic-grid" angular-grid="pics" grid-width="300" gutter-size="10" angular-grid-id="gallery" refresh-on-img-load="false" >
<li data-ng-repeat="item in data" class="grid">
<img src="{{item.url}}" class="grid-img" data-actual-width = "{{item.width}}" data-actual-height="{{item.height}}" />
</li>
</ul>
However, the items do not appear in the view, or should I say they are there but Angular-Grid and its CSS is not working as it does with the static array.
Here is the main part of the code.
Controller
var list = iService.getItems().$loaded()
.then(function(list) {
var cnt = list.length;
//console.log("cnt ", cnt);
angular.forEach(list,function(image,index){
//console.log('Item: ', list[index]);
var imageTemp = new Image();
imageTemp.onload = function(){
list[index].height = this.height + 'px';
list[index].width = this.height + 'px';
};
imageTemp.src = image.url;
cnt--
// test to see if all items have been iterated before setting $scope.data
if(!cnt){
console.log("done....", cnt);
console.log("ere ", list);
$scope.data = list;
} else {
console.log("Current cnt ", cnt);
}
});
Nothing displays, despite the JSON still appearing. Incidentally, the Angular-Grid class .grid-img has opacity:0 and visibility:hidden that when deactivated in dev tools show the items from Firebase but without the Angular-Grid resizing/styling.
It's probably not the best way to achieve it but I'm experimenting and feel the data coming from Firebase instead of a static array shouldn't make a difference. Anyone know what could be going wrong here? All help appreciated.Thanks!
The example in the documentation uses angular-grid="pics" in the ul attributes and $scope.pics=... in the controller.
angular-grid="pics" defines the model you want to listen
But you're setting $scope.data. Does that make any difference?
I recently inherited an asp.net project that uses Angular, which is very new to me, so I apologize in advance for any rudimentary questions or assumptions.
The markup / js below results in an endless number of the following error:
10 $digest() iterations reached. Aborting!
Angular version 1.2.27
I have the following markup (showing only relevant parts for brevity).
<div id="RecentContentGrid" ng-controller="RecentContentCtrl" ng-cloak>
<ul>
<li ng-repeat="item in items" ng-class="item.contentType.toLowerCase() && getItemClass(item)" ng-switch on="item.contentType">
<a href="{{item.url}}" class="content clearfix" title="{{item.displayName}}" ng-switch-default>
<img ng-src="{{getThumbUrlBySize(item, 320)}}?mh=320" />
</a>
</li>
</ul>
</div>
My issue is with the "ng-src="{{getThumbUrlBySize(item, 320)}}" part. This calls a method in the controller, which in turn calls a web service to get a image based on the specified height:
$scope.getThumbUrlBySize = function(item, size){
VideoThumbnail.query({ embedCode : item.embedCode, maxHeight: size }, function (data) {
return data.Content;
});
}
The controller also has the following watch methods:
// Watch Methods
$scope.$watch('params.category', function (newVal, oldVal) {
if (typeof(newVal) == 'string') {
$scope.params.perPage = $scope.total_items;
}
$scope.items = [];
});
$scope.$watchCollection('params', function () {
var items = [];
$q.all(_.compact([fetchArticles(), fetchVideos()])).then(function (data) {
items = _.flatten(data);
if (items.length == $scope.total_items) {
items = $filter('orderBy')(items, 'CreatedAt').reverse();
if (typeof(ad_content) != 'undefined' && ad_content.length > 0 && $scope.ads_served == false) {
items = injectAds(items);
}
for (i = 0; i < items.length; i++) {
items[i].cssClass = "block-" + (i + 1);
}
// Append scope items
$scope.items = $scope.items.concat(items);
}
else {
$scope.messages.push("No more items");
}
});
});
My question is how do I get a dynamic image url based on the specific item property and the passed in value for the size? As I mentioned, Angular is very new to me, so I'd appreciate specific details.
Oh, and I should that that the controller is used for many parts of the site, and that's why the size is passed in on the specific module, rather than at the scope level. The maxHeight variable will change based on where this module is used.
Thank you very much.
There are a couple of issues with your code I can see:
the function getThumbUrlBySize does not return anything. Therefore the markup {{getThumbUrlBySize(item, 320)}}?mh=320 fails to interpolate, leaving img tags with empty src attribute.
VideoThumbnail.query seems to be asynchronous. Even if it returned a Promise object, the markup wouldn't be interpolated with the resolved value.
The VideoThumbnail.query's callback does not actually do anything with the value it's passed (assuming that the method itself doesn't do anything with the value returned from its callback - which is unlikely)
None of these problems seems to cause an infinite $digest loop (from the code you've posted I'd suspect the injectAds function), however they prevent your code from working properly ;)
The easiest way I can imagine right now is to replace the for loop in $watchCollection handler with the following:
angular.forEach(items, function(item, i) {
item.cssClass = "block-" + (i + 1); // this comes from the original for loop
VideoThumbnail.query({ embedCode : item.embedCode, maxHeight: 320 }, function (data) {
item.thumbnail = data.Content + "?mh=320";
/*
VideoThumbnail.query accepts a callback instead of returning a Promise,
so we have to tell AngularJS to "refresh" when the asynchronous
job is done:
*/
$scope.$apply();
});
});
and the img markup:
<img ng-src="{{item.thumbnail}}" />
I wouldn't call this solution perfect, but it should work :)
Very noob here to Angular JS.
I'm working on a project and I have a solution to this, but I was wondering if theres a better approach
thats a bit more "angular-esque" if you will.
Essentially for each videoid, it performs an ajax request locating that videoid's image
and places that into the src attribute.
In pure javascript this would be no problem, and I've figured out one solution but it sort of deviates away from the angular approach.
I was wondering if it's possible to do something sort of what I have here. (obviously this doesnt work yet)
Markup
<ul class="storysContainer">
<li video-on-click ng-repeat="video in videos" id="video{{$index}}" >
<img ng-src="{{getVideoThumb()}}">
</li>
</ul>
JS
$scope.videos = [
{
'videoid': '1122345'
},
{
'videoid': '1134567'
},
{
'videoid': '2234456'
}
];
$scope.getVideoThumb = function() {
$.get("http://blahblah.com/id=" + url,function(data){
var urlMain = data.channel.item["media-group"]["media-thumbnail"]["#attributes"].url;
array.push(urlMain);
});
return array;
}
Thanks
edit:
This is the solution that i came up with..not sure if it's necessarily the best angular-esque appraoch, but it works.
angular.forEach($scope.videos, function(data) {
var dataid = "http://blablah.com?id=" + data.videoid;
console.log(dataid);
$.get(dataid, function(img){
var urlMain = img.channel.item["media-group"]["media-thumbnail"]["#attributes"].url;
$('#thumb' + data.videoid).attr('src', urlMain);
//array.push(urlMain);
});
});
I would declare the URL for each object within the videos object array. That way you can just bind the value in your presentation layer.
So maybe something like
$scope.videos = [
{
'videoid': '1122345'
},
{
'videoid': '1134567'
},
{
'videoid': '2234456'
}
];
//modified this a little. I take it this call accepts the videoID as a parameter
//and returns the url for a single video?
//I wasn't sure what the 'array' variable you were using was.
//I am also using angular $http service to make this ajax call
$scope.getVideoThumb = function(videoID) {
$http.get("http://blahblah.com/id=" + videoID).success(function(data){
var urlMain = data.channel.item["media-group"]["media-thumbnail"]["#attributes"].url;
return urlMain;
});
}
//iterate through each object and assign it a 'URL' property to the result of 'getVideoThumb(videoID)'
for(var i = 0; i < $scope.videos.length; i++){
$scope.videos[i].URL = $scope.getVideoThumb($scope.videos[i].videoid);
}
and now in our presentation layer we can just bind the value of URL to the ng-src
<li video-on-click ng-repeat="video in videos" id="video{{$index}}" >
<img ng-src="{{video.URL}}">
</li>
I'm trying to filter collections of data using quicksand.js. However, I'm having problems getting my data to appear. I have been able to get the data to disappear. Yet, it won't re-appear. I've created a jsfiddle, which is available here. Basically, my JavaScript looks like this:
var $content = $('#stage');
var $data = $content.clone();
function filterData(tag) {
var data = [];
if (tag === null) {
data = $data.find('li');
} else {
data = $data.find('li[data-tags=' + tag + ']');
}
console.log(data);
$content.quicksand(data, {
duration: 800,
easing: 'easeInOutQuad'
});
return false;
}
Everything looks correct to me. I can't figure out what I'm doing wrong.
First, your fiddle is broken. One, you link quicksand 1.3 and pair it with a recent jquery version it doesn't support. Two, you call out the easeInOutQuad without linking the jquery.easing.1.3.js. Three, you have scope issues, the filterData function is not defined globally.
Your real problem, though, is this line in the documentation:
attribute – attribute containing unique value able to identify same item within source and destination collection, default: 'data-id'
None of your "stage" data lis have this attribute so it won't filter them properly. Add it and all seems to work:
<ul id="stage">
<li data-tags="A" data-id="1">Item A-1</li>
<li data-tags="A" data-id="2">Item A-2</li>
<li data-tags="B" data-id="3">Item B-1</li>
<li data-tags="B" data-id="4">Item B-2</li>
</ul>
Updated fiddle.
I am using Restangular in my AngularJS app. I have a table with a delete link for each item. I would like to delete the item and have the row automatically removed. But as things are it only deletes from DB. How can I refactor things so that it the DOM is updated automatically?
// The controller
angular.module('myApp').controller('ManageCtrl', function($scope, Restangular) {
$scope.delete = function(e) {
Restangular.one('product', e).remove();
};
Restangular.all('products').getList({}).then(function(data) {
$scope.products = data.products;
$scope.noOfPages = data.pages;
});
});
// The view
<li ng-repeat="product in products">
</li>
I would also love to find an example of this - even with Angular resource. All the admin/data table demos seem to work from static data.
According to Restangular https://github.com/mgonto/restangular#restangular-methods they mention that you should use the original item and run an action with it, so in your html code you should:
<li ng-repeat="product in products">
</li>
Then in your controller:
$scope.delete = function( product) {
product.remove().then(function() {
// edited: a better solution, suggested by Restangular themselves
// since previously _.without() could leave you with an empty non-restangular array
// see https://github.com/mgonto/restangular#removing-an-element-from-a-collection-keeping-the-collection-restangularized
var index = $scope.products.indexOf(product);
if (index > -1) $scope.products.splice(index, 1);
});
};
Notice they use the underscore.js without which will remove the element from the array. I guess that if they post that example in their readme page that means the .remove() function doesn't remove the original item from the collection. This makes sense, since not every item you remove you want removed from the collection itself.
Also, what happens if the DELETE $HTTP request fails? You don't want to remove the item then, and you have to make sure to handle that problem in your code.
In my case the above didn't quite work. I had to do the following:
$scope.changes = Restangular.all('changes').getList().$object;
$scope.destroy = function(change) {
Restangular.one("changes", change._id).remove().then(function() {
var index = $scope.changes.indexOf(change);
if (index > -1) $scope.changes.splice(index, 1);
});
};