EmberJS sort Array Controller of Objects - arrays

Trying to figure this concept out. If you console.log this.get("content") before and after the sort, everything seems like it worked, but when it displays to the screen it gets funky. I think the issue is with Handlebars. When it "sorts" it adds a duplicate fourth record and sticks it at the top. You can see the problem in action here:
http://jsfiddle.net/skinneejoe/Qpkz5/78/ (Click the 'Sort by Age' text a couple times to resort the records and you'll see the issues)
Am I doing something wrong, is there a better way, or is this a bug? If it's a bug is there a good workaround?
Here's the full code:
index.html
<script type="text/x-handlebars">
{{#view App.SortView}}Sort by Age{{/view}}<br/>
{{#each App.userController}}
{{#view App.RecordView contentBinding="this"}}
{{content.name}} - {{content.age}}
{{/view}}
{{/each}}
</script>
app.js
window.App = Ember.Application.create();
App.userController = Ember.ArrayController.create({
content: [
Ember.Object.create({ name:"Jeff", age:24 }),
Ember.Object.create({ name:"Mark", age:32 }),
Ember.Object.create({ name:"Jim", age:12 })
],
sort:"desc",
sortContent:function() {
if (this.get("sort") == "desc") {
this.set("sort", "asc");
} else {
this.set("sort","desc")
}
if (this.get("sort") == "asc") {
var sortedContent = this.get("content").sort( function(a,b){
return a.get("age") - b.get("age");
})
} else {
var sortedContent = this.get("content").sort( function(a,b){
return b.get("age") - a.get("age");
})
}
this.set("content", []);
this.set("content",sortedContent)
}
})
App.RecordView = Ember.View.extend({})
App.SortView = Ember.View.extend({
click: function() {
App.userController.sortContent("poId")
}
})

I'm not seeing this bug in Safari, Chrome or Firefox on OS X, so I assume it's a IE issue.
Sounds a lot like this reported Ember bug, which got fixed 11 days ago. Try upgrading to ember-latest and see if that fixes it.

Related

Angular-Leaflet heatmap data update

I'm using the Angular-Leaflet directive to display a heatmap, and I want the data to evolve through time. My code looks like:
getData().then(function (data) {
$scope.heat.index = 0;
$scope.heat.data = data;
$scope.layers.overlays.heat = {
name: "Heatmap",
type: "heat",
data: $scope.heat.data[$scope.heat.index], // data is a dictionary, not an array
visible: true
};
$scope.$watch('heat.index', function (new_index) {
$scope.layers.overlays.heat.data = $scope.heat.data[new_index];
});
});
However, when I change data.index (through a slider), nothing happens. What could be going on? I know that Angular-Leaflet supports this behavior because of this Github issue where someone added it.
leafletData.getMap().then(function (map) {
map.eachLayer(function (layer) {
if (layer.options.layerName == 'heatmap') {
layer.setLatLngs(newHeatmapData);
}
})
})
This worked for me.
Leaflet.heat provides a redraw() method but that didn't work for me.

Capturing click events on clusters with markercluster and angular-leaflet-directive

I'm playing with the angular-leaflet-directive, and getting the marker names from a mouse click is straight forward. I just listen for the leafletDirectiveMarker.click event and then access args.markerName.
angular-leaflet-directive also works with markercluster, so I can cluster markers that have the same coordinates or ones that are close by. However, I would like to do the following, but it is not clear from the documentation on how to do it:
Make user double-click on cluster to zoom in. Currently doing a single click on a cluster will zoom in on the markers. see example.
How to listen for click event on cluster and get all marker names in the cluster.
The documentation for clustermarker has a cluster event:
markers.on('clusterclick', function (a) {
console.log('cluster ' + a.layer.getAllChildMarkers().length);
});
But I'm not sure what event I should be listening to using angular-leaflet-directive.
As far as your first question goes, you'll have to hook the doubleclick and pass it the fire('click') command after overriding the usual click event. Probably more trouble than its really worth, especially on mobile - and not something I can easily solve.
Regarding your second question, I have just solved it.
$scope.openMarker is a reference to an ng-click event in my jade template that is attached to an ng-repeat which pulls images and their id's from the database.
$scope.openMarker = function(id) {
var _this = [];
_this.id = id;
leafletData.getMarkers()
.then(function(markers) {
$scope.london = {
lat: $scope.markers[_this.id].lat,
lng: $scope.markers[_this.id].lng,
zoom: 19
};
var _markers = [];
_markers.currentMarker = markers[_this.id];
_markers.currentParent = _markers.currentMarker.__parent._group;
_markers.visibleParent = _markers.currentParent.getVisibleParent(markers[id]);
_markers.markers = markers;
return _markers;
}).then(function(_markers){
if (_markers.visibleParent !== null) {
_markers.visibleParent.fire('clusterclick');
} else {
_markers.currentMarker.fire('click');
}
return _markers;
}).then(function(_markers){
_markers.currentParent.zoomToShowLayer(_markers.markers[ _this.id ], function() {
$scope.hamburg = {
lat: $scope.markers[_this.id].lat,
lng: $scope.markers[_this.id].lng,
zoom: 19
};
if (_markers.currentMarker !== null) {
_markers.currentMarker.fire('click');
} else {
_markers.visibleParent.fire('clusterclick');
_markers.currentMarker.fire('click');
}
});
});
};
You can read more about how I came to this solution here at github.
Much like many people, I too had a long search with no results. While experimenting with another method, I came across this:
$timeout(function(){
leafletData.getLayers().then(function(layers) {
$scope.markerClusterGrp = layers.overlays.locations;
var clusters = $scope.markerClusterGrp.getLayers();
$scope.markerClusterGrp.on('clustermouseover', function (a) {
var clusterObjects = a.layer.getAllChildMarkers();
console.log(clusterObjects);
});
$scope.markerClusterGrp.on('clusterclick', function (a) {
var clusterObjects = a.layer.getAllChildMarkers();
console.log(clusterObjects);
});
});
},1000);
It works the same, the difference is that it requires a timeout in order to wait for the layer to render with all markers (my understanding, correct me if wrong :-) ).
I hope this helps anyone searching for an angular solution. Just remember to include $timeout in your controller dependencies.

Extended Select Dijit doesn't work in IE7

Why does this work in IE10 and Firefox but not in IE7/8?
Dojo version 1.8, using auto-require, extending a Select with a new missing message...
define([
"dojo/_base/declare",
"dijit/form/Select",
], function (declare, Select) {
return declare("mydijit.form.Select", [Select], {
missingMessage: "Please answer this.",
postMixInProperties: function(){
this.inherited(arguments);
this._missingMsg = this.missingMessage;
}
});
});
Fails in dojo.js
def (line 1801) => defineModule (line 1546) =>
getModule = function(mid, referenceModule, immediate){
....
match = mid.match(/^(.+?)\!(.*)$/); (line 1013)
For some reason mid is undefined.
Found the problem - if you look closely at the module list it contains a comma at the end of the list, which Internet Explorer 7 interprets as meaning an undefined field follows. Later versions of IE take it in their stride.
define([
"dojo/_base/declare",
"dijit/form/Select"
], function (declare, Select) {
return declare("mydijit.form.Select", [Select], {
missingMessage: "Please answer this.",
postMixInProperties: function(){
this.inherited(arguments);
this._missingMsg = this.missingMessage;
}
});
});

Backbone.history.navigate with IE <= 9

Having an issue with using Backbone history / push state - but only with browsers that don't support it (old IE)
The issue is this. When I visit /en_gb/dashboard for the first time - everything works, in all browsers. However, in IE<=9, it's appending #dashboard to the address bar, forming /en_gb/dashboard#dashboard. Now, when I hit refresh, my router is not triggering.
Not all my site is under Backbone control - so the router is working off:
routes: {
'dashboard': 'showDashboard'
}
My bootstrap looks like this:
if (Backbone.history) {
var pushStateSupported = _.isFunction(history.pushState);
var urlRoot = '/en_gb/';
var enableSilent = !pushStateSupported;
Backbone.history.start({
pushState: pushStateSupported,
root: urlRoot,
silent: enableSilent
});
if (!pushStateSupported) {
Backbone.history.navigate(window.location.pathname.substring(urlRoot.length), { trigger: true });
}
}
Adding debug, I can see Backbone.history.navigate() always being called but it seems the trigger: true is not being picked up when that hash is present.
Hmm - I seem to have fixed it - while not an elegant solution, this does solve it for me:
if (!pushStateSupported) {
var route = window.location.pathname.substring(urlRoot.length);
Backbone.history.navigate('/#' + route, { trigger: true });
}
It's not elegant in that the URL in the address bar appears as /en_gb/dashboard##dashboard - but it is now getting through the Backbone.navigate() method. Previously it was failing on
if (this.fragment === fragment) return;

Drupal.attachBehaviours with jQuery infinitescroll and jQuery masonry

I am a little desperate here. I have been reading everything I was able to find on Drupal.behaviours but obviously its still not enough. I try running a masonry grid with the infinitescroll plugin to attach the new images to the masonry. This works fine so far. The next thing I wanted to implement to my website is a hover effect (which shows information on the images) and later fancybox to show the images in a huger size.
(function ($) {
Drupal.behaviors.views_fluidgrid = {
attach: function (context) {
$('.views-fluidgrid-wrapper:not(.views-fluidgrid-processed)', context).addClass('views-fluidgrid-processed').each(function () {
// hide items while loading
var $this = $(this).css({opacity: 0}),
id = $(this).attr('id'),
settings = Drupal.settings.viewsFluidGrid[id];
$this.imagesLoaded(function() {
// show items after .imagesLoaded()
$this.animate({opacity: 1});
$this.masonry({
//the masonry settings
});
});
//implement the function of jquery.infinitescroll.min.js
$this.infinitescroll({
//the infinitescroll settings
},
//show new items and attach behaviours in callback
function(newElems) {
var newItems = $(newElems).css({opacity: 0});
$(newItems).imagesLoaded(function() {
$(newItems).animate({opacity: 1});
$this.masonry('appended', newItems);
Drupal.attachBehaviours(newItems);
});
});
});
}
};
})(jQuery);
Now I read that I need to Reattach the Drupal.behaviours if I want the hover event to also take place on the newly added content.
(function ($) {
Drupal.behaviors.imgOverlay = {
attach: function (context) {
var timeout;
$('.img_gallery').hover(function() {
$this = $(this);
timeout = setTimeout(change_opacity, 500);
}, reset_opacity);
function change_opacity() {
//set opacity to show the desired elements
}
function reset_opacity() {
clearTimeout(timeout);
//reset opacity to 0 on desired elements
}
}
};
})(jQuery)
Where do I now write the Drupal.attachBehaviours() to make it work actually? Or is there some other error I just dont see atm? I hope I wrote the question so that its understandable and maybe it also helps somebody else, since I experienced that there is no real "official" running Version of this combination in drupal 7.
Ok, the solution is actually pretty simple. When writing it correctly than it also runs. its of course not Drupal.attachBehaviours() but Drupal.attachBehaviors() . So this combination now works and I am finally relieved :).

Resources