How to clear backbone collection before fetching new data? - javascript

Hi all i have been working on backbone application where images are being added and existing images are being deleted or edited. Now am using router for the various section like gallery, forms but when i edit something in gallery goes back to forms and come back i am not getting the changes that i have done earlier. Instead it shows old data. I need to refresh i mean CTRL+F5 to see that changes which is not good.
I tried the .clear and .reset its resetting the collection and model but doesn't effects the data inside the collection. Can any one please help me that where i am going wrong.
Below is code for Collection and model :
var GalleryImage = Backbone.Model.extend({});
var GalleryImages = Backbone.Collection.extend({
model : GalleryImage,
url: '######',
initialize : function(){
this.reset();
if(this.reset())
{
console.log("model reset", GalleryImage.cid)
}else{
console.log("model not set")
}
this.on("reset", this.loadImagesView,this);
this.on("error", this.errorMessage,this);
//console.log(GalleryImages.get(0))
},
loadImagesView : function(){
//console.log(this);
//console.log(this.CollView.$el);
if(!this.CollView){
this.CollView = new GalleryImagesView({collection:this})
}
this.CollView.render();
},
errorMessage : function(){
jQuery('#imageBlocksDiv').html('<span id="noMsg"><h4>No images to display.</h4></span>');
}
});
And for the router is :
initGallery : function(){
jQuery('#invset').hide();
jQuery('#imagelist').children().eq(0).append(jQuery('.floor_img').find('#box').css({'z-index':'1','position':'relative','margin-top':'0px','margin-left':'0px'}));
pinterest(undefined);
jQuery("#box").show();
jQuery('#invset').hide();
jQuery('#inventorycontent').hide();
jQuery("#boxnews").hide();
jQuery("#boxzip").hide();
jQuery(".select").attr('style','display:block');
jQuery(".select").attr('id','ugallerygal');
jQuery(".pagetitle").html('Gallery');
var that = this,projectId = jQuery('#ugallerygal').val();
jQuery('#imageBlocksDiv').html('');
var imgObj = new GalleryImages();
//this.reset(imgObj);
imgObj.fetch({data: jQuery.param({projectId: projectId, add:true, reset:true}), success:function(){
console.log(imgObj)
imgObj.trigger("reset");
},
error : function(){
imgObj.collection.trigger("error");
}
});
},
Not only this i have a section that when user click on images the image open up and by clicking anywhere on image the can place a point and add details in that point which i am storing in parse, However the value on changes get saved but when i come back to the image the older position and number images are displayed instead of the newer one and updated point that are stored in parse. I guess the issue is same for both state so the the solution for one will work for all.
Any help is deeply appreciated. Thanking in advance
Thanking you,
Santosh Upadhayay

Problem could be with the order of reset and adding reset listener. Try changing
this.reset();
if(this.reset())
{
console.log("model reset", GalleryImage.cid)
}else{
console.log("model not set")
}
this.on("reset", this.loadImagesView,this);
this.on("error", this.errorMessage,this);
to
this.on("reset", this.loadImagesView,this);
this.on("error", this.errorMessage,this);
this.reset();
if(this.reset())
{
console.log("model reset", GalleryImage.cid)
}else{
console.log("model not set")
}

Related

Node / Express - Append information to list when user hits bottom of page using Snoocore (Reddit API wrapper)

I am working on a private application of a food sub reddit, what I'm retrieving some images witha limit of 20 images per view and when the user reach the bottom of the page it loads more information and appends it, like ajax; I'm doing the request server side and using Snoocore which is an API wrapper for Reddit. Snoocore actually provides a method to fetch information of the next page. From Snoocore's documentation:
// Instead of an HTTP verb, use a Snoocore helper `.listing`
// It will return a "slice" for a listing that has various
// helpers attached to it.
reddit('/r/askreddit/hot').listing().then(function(slice) {
// This is the front page of /r/askreddit
// `slice.children` contains the contents of the page.
console.log(slice.children);
// Get a promise for the next slice in this
// listing (the next page!)
return slice.next();
}).then(function(slice) {
// This is the second page of /r/askreddit
console.log(slice.children);
});
And this is my code:
reddit('/r/food/hot').listing({limit: 10}).then(result => {
for (var x in result.children){
if (result.children[x].data.link_flair_text === '[Homemade]' || result.children[x].data.link_flair_text === '[homemade]') {
if (result.children[x].data.domain !== 'imgur.com') {
if (result.children[x].data.post_hint !== "rich:video") {
titles.push({
'title': he.decode(result.children[x].data.title),
'imgurl': he.decode(result.children[x].data.url),
'user': result.children[x].data.author,
'submission': result.children[x].data.permalink
});
}
}
}
}
console.log(result.children[4].data);
res.render('index', {
'titleArr': titles
});
});
on my Pug template I have:
extends layout
block content
div#wrap
each i in titleArr
figure.figure
img.img-fluid.img-rounded(src= i.imgurl)
figcaption.figure-caption.text-center
p.text-muted #[i #{i.title}]
p
| #[i ―by ]
a(href="http://reddit.com" + i.submission, target="_blank")
| #[i /u/#{i.user}]
listing({limit: 10}) here is important because, well, it limits the post retrieved; actually I'm retrieving only 10, by default it retrieves 25; anyway, I'm looking for a way, how i said that when the user reach bottom of the page it loads more post; do I have to do this via client side? Or can I do this via server side in some way? Tell me if I need to explain my issue more in depth.
What you are looking for is "infinite scrolling", you basically want to do another request when your user reaches the bottom of the page that has been rendered.
This is going to require you to fire an ajax request when your browser scroll reaches the bottom of the page. If you were to use jQuery, your code would look something like this:
$(document).ready(function() {
var win = $(window);
var parts = location.pathname.split("/");
// assuming a url like domain.com/reddit/10 where 10
// is the total number of posts you're showing
var pageNumber = parts[3]; //this gives you access to the `10`
// then add 10 to the current page number and
pageNumber += 10
// use that for your ajax request
var url = "http://domain.com/reddit/"+pageNumber;
// Each time the user scrolls
win.scroll(function() {
// End of the document reached?
if ($(document).height() - win.height() == win.scrollTop()) {
$('#loading').show();
$.ajax({
url: url,
dataType: 'json',
success: function(json) {
// do something with your json of your posts
// then hide the loading gif or image.
$('#loading').hide();
}
});
}
});
});
This will fire the ajax request whenever your user reaches the bottom of the page, and paginate correctly. This is only the browser side, though.
You will need to edit your server endpoint slightly as well.
For example, you need to increase your limit dynamically
//you could use the req.params method from express to accomplish this
reddit('/r/food/hot').listing({limit: req.params.limit}).then(result => {
for (var x in result.children){
if (result.children[x].data.link_flair_text === '[Homemade]' || result.children[x].data.link_flair_text === '[homemade]') {
if (result.children[x].data.domain !== 'imgur.com') {
if (result.children[x].data.post_hint !== "rich:video") {
titles.push({
'title': he.decode(result.children[x].data.title),
'imgurl': he.decode(result.children[x].data.url),
'user': result.children[x].data.author,
'submission': result.children[x].data.permalink
});
}
}
}
}
console.log(result.children[4].data);
res.render('index', {
'titleArr': titles
});
});
Accessing the req.params.limit variable should work. You will need to edit your endpoint definition as well. I'm not sure how you have your server's routing setup right now, but this would be one way you could do it:
app.get('/reddit/posts/:limit', function(req, res) {
console.log('limit is: ', req.params.limit);
})
The idea here is that you want to increase the number of items you're fetching with each jQuery request. this is a pretty quick and dirty way of doing so, and I'm making some assumptions about how you're handling the server and what you're using, but this should get you 90% of the way there. Hope this helps!

JQuery doesn't work with the after created element

I want to create some css card with the data retrieved from json. It iterates fine, but I have a problem with the animation. When the user press a button, the card makes an animation and shows more info. The problem is that the animation works just with the first card. How can I solve it? Thank you.
HERE you can find the full code.
This is the script linked to the info's button:
(function(){
'use strict';
var $mainButton = $(".main-button"),
$closeButton = $(".close-button"),
$buttonWrapper = $(".button-wrapper"),
$ripple = $(".ripple"),
$layer = $(".layered-content");
$mainButton.on("click", function(){
$ripple.addClass("rippling");
$buttonWrapper.addClass("clicked").clearQueue().delay(1500).queue(function(){
$layer.addClass("active");
});
});
$closeButton.on("click", function(){
$buttonWrapper.removeClass("clicked");
$ripple.removeClass("rippling");
$layer.removeClass("active");
});
})();
ok your issue is you not detect good element. i have modify your script.js
$(document).on("click",".main-button", function(){
$(this).find(".ripple").addClass("rippling");
$(this).closest("main").find(".button-wrapper").addClass("clicked").clearQueue().delay(1500).queue(function(){
$(this).closest("main").find(".layered-content").addClass("active");
});
});
please try: http://plnkr.co/edit/qZmi3jJS4WVcN676OSP2
UPDATE for close
Try
$(document).on("click",".close-button", function(){
$(this).closest("main").find(".button-wrapper").removeClass("clicked");
$(this).closest("main").find(".ripple").removeClass("rippling");
$(this).closest("main").find(".layered-content").removeClass("active");
});
link : http://plnkr.co/edit/WKtJUqOwkEGnhb2Zc1HZ

DOM Elements loaded from ajax and (probably) not ready in time

I'm using sorting/filtering jQuery plugin Isotope and also jQuery $.ajax() to dynamically load some new elements to the page that need to be sorted with Isotope. That library seems to set all the new sorted elements with absolute position and with fixed (left, top) position in order to perform sorting.
The problem is that when you load the first set of elements with clear cache the the element positions in that absolute grid are incorrect (they are overlapping). This is caused by Isotope initialization. My (inexperienced) guess would be that the all the new DOM elements are not fully loaded by the time Isotope starts to calculate the future positions of the elements and there's where the in-accuracy comes in. If I do the exact same ajax request again it manages to calculate the positions correctly.
EDIT #1 ajax reuqest
var $isocont = $('#page-content-result');
var isoActive = false;
$.ajax({
url: actionUrl + 'ajax',
type: 'POST',
data: searchData,
success:function (data) {
if(data.trim().length > 0) {
$('#page-content-result').hide().empty().html(data).fadeIn(600);
initIsotope();
} else {
var visible = $('#page-content-result').is(':visible');
if(visible === true)
{
$('#page-content-result').empty();
}
$('#result-notif').show();
}
}
});
var initIsotope = function() {
if(isoActive === true) {
$isocont.isotope('destroy');
console.log('iso stop');
isoActive = false;
}
if(isoActive === false) {
$isocont.isotope({
getSortData: {
name: '.iso-docname',
}
});
console.log('iso start');
isoActive = true;
}
}
Can someone explain the nature of this problem and give few hints for solution?
Thnx!
Seems that once again the "morning is smarter than the night" (it's a saying in Estonian :P).
I placed a piece of test-code after part where the new data was inserted to the DOM.
if (/complete/.test(document.readyState)) {
alert('loaded');
}
The alert kind of pauses the loading of the page and I realized that the containers where quite a lot shorter because of the not-yet-loaded images. Meaning the DOM doesn't have the information how high the containers are going to be when we initialize the Isotope and that's why the Isotope fails to calculate the correct positions.
FIX: After understanding the problem the fix is really simple just tell the DOM how high the image is going to be in CSS with min-height: 122px; and that is all. I guess if the image height varies then I believe setting an interval checker for document.readyState == 'loaded' would help.
Idea came from that blog http://callmenick.com/2014/06/04/check-everything-loaded-javascript/
So my general js file now looks something like that:
var $isocont;
$(document)(function() {
//When DOM create a var of selector.
$isocont = $('#page-content-result');
//One time aka first init of Isotope with basic options.
$isocont.isotope({
getSortData: {
name: '.iso-docname',
}
});
$.ajax({
url: actionUrl,
type: 'POST',
data: searchData,
success:function (data) {
if(data.trim().length > 0) {
//Set HTML data from ajax request
$('#page-content-result').hide().empty().html(data).fadeIn(600);
//Reload isotope items and re-arrange the items according to config.
reloadIsotope();
} else {
//DO SMTH
}
}
});
});
var reloadIsotope = function() {
$isocont.isotope('reloadItems');
//We are resetting sorting since we might not want same ordering as on last result.
$isocont.isotope({sortBy: null, sortAscending: true});
}
Thanx TimSPQR for looking into!

Learning Ember.js- Persistence In Many To Many Relationships

To learn Ember.js I started writing a small bookmark application. I'm struggling with issues related to wrong data handling now.
To Explain The Application
User can add label
User can add links to selected labels
A Label can have n links
A Link can have n labels
Show links by selecting the associated labels
The Issue
Link data is not writtern to the data store. Because of this, local updates to the links model due selection changes are overwritten. Also, implementing true persistence later wouldn't work.
Narrowing down the issue
In IndexRoute I initialize the model:
model: function(params) {
return {
labels: this.get("store").find("label"),
// TODO: this is probably wrong.
links: Ember.A()
};
}
On the one side I fetch label data from the data store. On the other side I initialize link data with an empty ember array.
In my opinion this is the root of the malfunction but I don't know how to implement this properly.
I tried to replace this with bogus references to the storage adapter:
this.get("store").find("label").filter("_")
This is neither right nor does it work properly. Then it continues to the point where I then can't use the storage adapter to update records:
// TODO: this is probably wrong.
this.get("links").addObject({
name: linkName,
url: linkUrl,
labels: this.selectedLabels
});
/*store.push("link", {
name: newLink,
url: linkUrl,
labels: this.selectedLabels
});*/
And so on.
Jsbin: http://jsbin.com/ucanam/1751/edit
How to store link data properly so changing the local data of the controler won't break the application?
Edit:
I think I found my conceptual mistake with your advice. Does that mean that I always have to handle the local copy aswell?
var link = this.get("model");
link.deleteRecord();
link.save().then(function(link) {
var indexController = this.get('controllers.index');
indexController.get("links").removeObject(link);
});
In your example you used a promise to add the object to the controller. In this code sample the promise will never fulfill- therefore it only works without.
Also in the LabelController the remove method should also deletes associated links. If I use deleteRecord in the forEach loop it only deletes one label and then it somehow brings the loop to exit. Is this intentionally or have I made a mistake?
I have updated your JsBin.
http://jsbin.com/ucanam/1987/edit
I modified your JSbin http://jsbin.com/ucanam/1975/
If you want to persist records you must create them in the store with createRecord() and then save() them. The new newLink function
newLink: function() {
var store = this.get("store"),
linkName = this.get("linkName"),
linkUrl = this.get("linkUrl"),
links = this.get("links"),
selectedLabels = this.get('selectedLabels');
if(selectedLabels.get('length') > 0) {
if(linkName.length > 0 && linkUrl.length > 0) {
var newLink = store.createRecord('link',
{
name: linkName,
url: linkUrl
});
selectedLabels.forEach(function(label){
newLink.get('labels').addObject(label);
});
newLink.save().then(function(link){
links.addObject(link);
});
this.set("linkName", "");
this.set("linkUrl", "");
}
} else {
alert("You have to select a label!");
}
},
For deleting records there are problems using forEach because the result of a find to the store is a live array. You can see this discussion in GitHub https://github.com/emberjs/data/issues/772.
So your remove label function should be (note the use of toArray() to make a static copy of the live array)
remove: function() {
var indexController = this.get('controllers.index'),
label = this.get('model'),
linksPromise = this.get('store').find('link');
linksPromise.then(function(links){
links.toArray().forEach(function(link){
var linkLabels = link.get('labels'),
linkLabelsIds = linkLabels.mapProperty('id');
if(linkLabelsIds.contains(label.get("id"))) {
if(linkLabelsIds.get("length") == 1) {
console.log("delete link: "+link.get("name"));
indexController.get("links").removeObject(link);
link.deleteRecord();
link.save();
}
}
});
label.deleteRecord();
label.save();
});
}
Final note, don't forget to make a save() on the records after deleting them, jsBin here: http://jsbin.com/ucanam/1989/
Have you defined your models?
App.Label = DS.Model.extend({
title: DS.attr('string'),
links: DS.hasMany('link')
});
App.Link = DS.Model.extend({
name: DS.attr('string'),
url: DS.attr('string'),
labels: DS.hasMany('label')
});
App.IndexRoute = Ember.Route.extend({
model: function() {
this.store.find('label')
}
});
App.LabelController = Ember.ObjectController.extend({
actions:
<!-- functions here -->
});
<script type='text/handlebars' data-template-name="index">
{{#each label in model itemController='label'}}
{{label.title}}
{{#each link in label.links}}
{{link.title}}
{{/each}}
{{/each}}
</script>

JQuery/Javascript works on & off

I am using JQuery 1.3.2-min in a project to handle JavaScript animations, ajax, etc. I have stored the file on the same server as the site instead of using Google. When I run the site locally on my development machine, everything works fine in FF, IE, Opera, and Safari (all the latest versions - I work from home and I only have 1 machine for personal use and development use) except for some CSS differences between them and when I go to the live site on my machine it works fine also. I have cleared my caches and hard refreshed the page, and it still works.
This is where it gets interesting however. When I send the site to my boss to test in various OS/Browser configurations, one page doesn't work correctly, some of it works, some doesn't. Also, the client (who uses IE 8) has also confirmed that it is not completely working - in fact he has told me that the page will work fine for a hour, and then just "turn off" for a while. I have never heard of this sort of thing before, and google isn't turning too much up. I have a hunch it may partly be with JQuery's .data(), but I'm not sure.
The page is basically nested unordered lists, and three basic actions happen on the list.
The top most unordered list is set to visible (all list via css are set to display: none to keep them hidden on a fresh page request); all list items divs are given a hover action of full opacity on mouseon, and faded back to 50% opacity on mouseoff; and then whenver a paragraph is clicked, the top most unordered list in that list item is displayed.
Here is my Javascript file for the page:
$(function() {
// Set first level ul visible
$('div#pageListing ul:first').css('display', 'block');
// Disable all the hyperlinks in the list
$('div#pageListing li a').click(function() {
var obj;
obj = $(this).parent(0).parent('div:first');
highlight(obj);
return false;
});
// List Item mouse hovering
$('#pageListing li').hover(
// Mouse On
function() {
if ($(this).children('div').attr('id') !== 'activePage') {
$(this).children('div').css('opacity', 1).css('filter',
'alpha(opacity=100)');
}
}, // Mouse off
function() {
if ($(this).children('div').attr('id') !== 'activePage') {
$(this).children('div').css('opacity', 0.4).css('filter',
'alpha(opacity=40)');
}
});
// Active list item highlighting
$('#pageListing li div').click(function() {
highlight($(this));
});
// Sub-list expanding/collapsing
$('#pageListing p.subpageslink').click(function() {
// Get next list
var subTree = $(this).parent('div').next('ul');
// If list is currently active, close it, else open it.
if (subTree.data('active') != true) {
subTree.data('active', true);
subTree.show(400);
} else {
subTree.data('active', false);
subTree.hide(400);
}
});
// Double clicking of list item - edit a page
$('#pageListing li div').dblclick(function() {
var classes = $(this).attr('class');
var classArray = classes.split(' ');
var pageID = classArray[1];
editPage(pageID);
});
// Handle button clicking
$('button#addPage').click(function() {
addPage();
});
$('button#editPage').click(function() {
var div = $('div#activePage');
var classes = div.attr('class');
var classArray = classes.split(' ');
var pageID = classArray[1];
editPage(pageID);
});
$('button#delPage').click(function() {
var div = $('div#activePage')
var classes = div.attr('class');
var classArray = classes.split(' ');
var pageID = classArray[1];
delPage(pageID);
});
});
// Highlighting of page when clicked
function highlight(obj) {
// Get previous hightlighted element
// and un-highlight
var oldElement = $('div#activePage');
oldElement.css('background', 'white');
oldElement.css('opacity', 0.4).css('filter', 'alpha(opacity=40)');
oldElement.removeAttr('id');
// highlight current selection
obj.attr('id', 'activePage');
obj.css('opacity', 1).css('filter', 'alpha(opacity=100)');
obj.css('background', '#9dc0f4');
// add appropiate action buttons
$('button.pageButton').css('display', 'inline');
}
function addPage() {
window.location = "index.php?rt=cms/editPage";
}
function delPage(page) {
var confirm = window.confirm("Are you sure? Any sub-pages WILL BE deleted also.");
if (confirm) {
var url = './components/cms/controller/forms/deletePage.php';
$.ajax( {
url : url,
type : 'GET',
data : 'id=' + page,
success : function(result) {
if (!result) {
document.location = "index.php?rt=cms";
} else {
window.alert('There was a problem deleting the page');
}
}
});
}
}
function editPage(page) {
var url = "index.php?rt=cms/editPage/" + page;
window.location = url;
}
Is it possible that you are linking to (some of) the script files using a src that points to a file on your local disk/HDD? If so, that would explain why it works only on your machine, as then only your machine has access to the script file.
Thank you one and all for your suggestions. The end problem was miscommunication. I work from home, and upload my projects to a SVN server, which the boss then uses to update the live server. Somehow, the correct files were not getting updated - a communication error on my part. Another possible reason was that the page, while being declared XHTML 1.0 Strict, had something like 50 validation errors (mosting incorrectly nested UL), and I cleaned that up to 5 errors. So thank you all, but again a sad example of the importance of team work communication.

Categories

Resources