Items from Firebase not displaying in Angular Grid - javascript

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?

Related

Updating Json Data for angular-flexslider breaks on 'removeSlide'

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; }`

Unable to get Quicksand.js working

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.

jQuery - remove li from array with delete image

I'm attempting to make a menu bar that can have <li> elements added and removed. So far so good, but when I try and remove them I'm running into issues. I've toyed with this for a couple hours and now I'm wondering if this whole process could just be made easier (maybe an object?).
Anyways, here's the full code (80 lines), with comments to follow along.
var tabs = $('.accountSelectNav');
var titles = [];
var listItems = [];
// when the page loads check if tabs need to be added to the ul (menu bar)
$(document).ready(function(e) {
if ($.cookie('listItems') != null) {
console.log('not null');
//return "listItems" to it's array form.
listItems = JSON.parse($.cookie('listItems'));
$('.accountSelectNav').append(listItems);
}
});
$('.selectTable td:first-child').on('click', function(e) {
$('#home_select').removeClass('navHighlight');
//grab the text value of this cell
title = $(this).text();
$.ajax({
url:'core/functions/getAccountId.php',
type: 'post',
data: {'title' : title}
}).fail (function() {
alert('error');
}).done(function(data) {
accountId = $.trim(data);
// store values in the cookie
$.cookie('account_id', accountId, {expires : 7});
$.cookie('title', title, {expires : 7});
window.location = ('home_table.php');
});
// make sure the value is NOT currently in the array. Then add it
var found = jQuery.inArray(title, titles);
if (found == -1) {
titles.push(title);
addTab();
}
// make sure the value is NOT currently in the array. Then add it
found = jQuery.inArray(title, listItems);
if (found == -1) {
addListItem();
//place <li>'s in cookie so they may be used on multiple pages
$.cookie('listItems', JSON.stringify(listItems));
};
});
$("body").on("click", ".deleteImage", function (e) {
var removeTitle = $(this).closest('li').find('a').text();
var removeItem = $(this).closest('li')[0].outerHTML;
//remove title from "titles" array
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
//remove <li> from "listItems" array
listItems = jQuery.grep(listItems, function (value) {
return value != removeItem;
});
// this shows the <li> is still in the listItemsarray
console.log(listItems);
// put the array back in the cookie
$.cookie('listItems', JSON.stringify(listItems));
removeTab(this);
});
$("body").on("mouseover", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').show();
});
$("body").on("mouseleave", ".accountSelectNav li", function(e) {
$(this).find('.deleteImage').hide();
});
function addTab() {
tabs.append('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
};
function removeTab(del) {
$(del).closest('li').remove();
}
function addListItem() {
var s = ('<li class="navHighlight">' + '' + title + '' + '' + '<img src="images/delete.png" class="deleteImage"/>' + '' + '</li>');
listItems.push(s);
}
So you see I have two arrays of equal length that should always be the same length. One stores the title to be displayed in the tab, the other holds the html for the <li> which will be appended to the <ul>. I have no problem removing the title from its array. However removing the <li> from it's array is becoming a rather big hassle. You see when I get the <li> element after its been inflated the html inside does not exactly match what was put in, the browser adds style elements.
Example, the variable "removeItem" represents the html value of the selected <li> I wish to remove. It looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage" style="display: inline;"></li>
yet the value in my array "listItems" looks like this:
<li class="navHighlight">Test1<img src="images/delete.png" class="deleteImage"/></li>
So my attempt at removing it from my array always fails because they aren't a perfect match.
Now my question is how do I remove this <li> item? Also is there an easier way to do this whole process and I'm just not seeing it?
Thanks for your time.
EDIT
Fiddle by request here
Easiest way I can explain it.
Click the link to the fiddle.
Click any cell in the "App Name" column
This will add a <li> to the <ul> (menu) above of the table
When you hover over the <li> a picture appears
Click the picture
This should remove the <li>, both from the <ul> and from the array listItems
right now it does not
In the process of making this easier to check, I've taken your JSFiddle and did the following:
removed extra console.log and comments
removed interaction with cookies (since I did not have them in the first place, I figured they wouldn't just the first scenario)
After doing so I reached a point (you can see it here) where the desired functionality just works.
I even went ahead and removed the ajax stuff because that alert was driving me crazy. (here)
Since this works fine, my guess is that your issue lies between the lines that I removed.
Your usage of cookies is as follows:
To load existing tabs and add them back again
To save account_id and title, which is not used back again
To persist the listItems after a new item has been added
I then opened up the console with your version of the fiddle and the execution of javascript stops at $.cookie() with the error undefined is not a function.
This clearly indicates that the issue present in the Fiddle is that jQuery.cookie is not present and so those calls are halting the execution of the rest of your script. This also explains why it just started working when I took them out.
I posted the whole process of how I got there to indicate how I trimmed down the problem to specific parts, which is useful to reduce the problem space. When you're out of options and reach a place when you're lost, it's easier to post a question with less code and the specific part of the problem that you've identified. This will help you in finding the issues that you're facing and StackOverflow to provide proper answers to your questions.
Hope it helps!
Here is the solution I came up with. It should be much easier for people to understand than my original post. Although it's a long read it may be worth it, especially for new developers.
The point of this code is to make a menu bar out of an un-ordered list or <ul>. The menu bar needs to be used on multiple pages. So I'll be using cookies.
I start with this code to get a text value from my table.:
$('.selectTable td:first-child').on('click', function(e) {
// This value will be used later for the name of the tab or `<li>` inside our menu bar or `<ul>`
title = $(this).text();
});
Then I place the value in an array. I do this only if the array does not already have this string inside it. I do not want duplicates:
var found = jQuery.inArray(title, titles);
var titles = [];
if (found == -1) {
titles.push(title);
}
Then I store the array into a cookie, using a library like this:
$.cookie('titles', JSON.stringify(titles));
Now when any page loads that needs this menu bar I run this code to check if there are any values:
$(document).ready(function() {
if ($.cookie('titles') != null) {
titles = JSON.parse($.cookie('titles'));
}
});
Now I need to loop through the array. When I loop through the array I have to do 3 things:
1) Grab the string value.
2) Add the html to my new string so it becomes a list item or <li>.
3) Append the newly created <li> to our <ul>.
Like so:
for(var i = 0; i < titles.length; i++) {
var str = titles[i];
var listItem = '<li class="navHighlight">'
+ '<a href="#">'
+ str
+ '</a>'
+ '<a href="#">'
+ '<img src="images/delete.png" class="deleteImage"/>'
+ '</a>'
+ '</li>';
$('.accountSelectNav').append(listItem);
}
Now, if I want to remove this <li> I click the delete image found inside our <li>. What delete image you say? Look at the html I added again. You will see I add an <img> tag in there.
Now delete like so:
$("body").on("click", ".deleteImage", function (e) {
// grabs the text value of my li, which I want to remove
var removeTitle = $(this).closest('li').find('a').text();
// runs through my titles array and returns an array without the value above
titles = jQuery.grep(titles, function (value) {
return value != removeTitle;
});
});
Then I simply place the new array inside my cookie once again. Like this:
$.cookie('titles', JSON.stringify(titles));
And finally I remove the tab like this:
removeTab(this);
function removeTab(del) {
$(del).closest('li').remove();
}
Yay, I'm done. So now, if anyone has a more elegant way of accomplishing this I'm listening. I have no doubt there's a better way, javascript/jQuery isn't even close to my strong point.
The full code can be found here.

Deleting entry with Restangular

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);
});
};

WinJS.UI.ListView - refreshing items when using template is built using javascript

I've got a ListView that was using HTML-defined templates like this:
<div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template">
<div>
<!-- Displays the "picture" field. -->
<img data-win-bind="alt: title; src: picture" />
<div>
<!-- Displays the "title" field. -->
<h4 data-win-bind="innerText: title"></h4>
<!-- Displays the "text" field. -->
<h6 data-win-bind="innerText: description"></h6>
</div>
</div>
</div>
<div id="basicListView" data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource : DataExample.itemList.dataSource, itemTemplate: select('#mediumListIconTextTemplate')}">
</div>
When my list items changed, my item template would be updated to reflect the change. However, out of need, I had to change to using a javaScript function to build my template. I modeled my code after the code found on the sample site:
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll().then(function () {
var lView = document.getElementById("templateFunctionListView").winControl;
lView.itemTemplate = itemTemplateFunction;
}));
}
};
function itemTemplateFunction(itemPromise) {
return itemPromise.then(function (item) {
var div = document.createElement("div");
var img = document.createElement("img");
img.src = item.data.picture;
img.alt = item.data.title;
div.appendChild(img);
var childDiv = document.createElement("div");
var title = document.createElement("h4");
title.innerText = item.data.title;
childDiv.appendChild(title);
var desc = document.createElement("h6");
desc.innerText = item.data.text;
childDiv.appendChild(desc);
div.appendChild(childDiv);
return div;
});
};
After changing to the javascript function, my display items never change when my binding data changes.
What do I need to do to make them update?
I think there are two approaches that could work for you.
In my case, when I refresh the data for my app, it's possible that one or more entities may be completely out of date, and there may be new entities to display. So I simply re-set the binding of the ListView, like so:
listView.itemDataSource = Data.items.dataSource;
where Data is the namespace I set up in data.js to contain all my data functions and objects.
When I update the value of the itemDataSource property, the ListView will re-bind to the new data, and display the correct items.
The other thing to look at, if your data is only being updated one property at a time, is using the WinJS.Binding.as function to make the items in the binding list observable, as described here:
http://msdn.microsoft.com/en-us/library/windows/apps/hh781224.aspx#updating_changing_records
If you haven't seen it already, there's some good info on databinding here:
http://msdn.microsoft.com/en-us/library/windows/apps/hh758311.aspx
And I found the following MSDN forum thread that may be helpful:
http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/21b9603f-e28d-4c93-b164-a2c91ba5c4ca
Hope the above helps!
For more information on Windows Store app development, register for App Builder.
Instead of rebinding the whole data set you can just rebind the single item. Find the items position in the list and then splice it replacing it with itself.
for (var i = 0; i < list.length; i++){
item = list.getAt(i);
if (item.key == itemToBeReBound.key){
list.splice(i, 1, item);
i = list.length;
}
}

Categories

Resources