AngularJS: Google Map Not Appearing - angularjs

I'm trying to use Angularjs-Google-Maps in comibination with ui-router. I'm getting a weird issue where the map is only partially appearing.
I've managed to resolve it by creating a directive that triggers a 'resize' event to repaint the map:
function autoRefresh() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$on('$stateChangeSuccess', function(){
google.maps.event.trigger(scope.map, 'resize');
console.log("this works!");
});
}
}
}
<map center="-34.397, 150.644" zoom="8" auto-refresh></map>
And this works great, once the initial page has loaded and I change the state, the map appears. But if I simply do a hard reload of the page in the browser, the map doesn't appear. I have to change the state before the map is visible.
Is there an alternative to '$stateChangeSuccess' that works on initial page load?
Any help is appreciated. Thanks in advance!

Related

How to hook to "OnOpen" listener for uib-popover?

Context: I am using angular 1 and this UIB Popover control.
Since there is a text field in the popover template I called, my target is to focus on that text field whenever the popover is opened.
Unfortunately, there is no popover listener/event for "onOpen".
So I tried to do a
scope.$watch(()=>{return scope.isOpen}, (obj) ={
// where scope.isOpen is the local var in the popover-is-open
// expecting to write some code here to manipulate the element
// to realise the focus operation
// but there is no popover element yet when this is called
})
I was just wondering what other options I might have?
Thanks
I found nothing on the documentation talked about events and found this issue on the ui-bootstrap github stating that they do not support events nor do they ever plan to implement them. https://github.com/angular-ui/bootstrap/issues/5060
If you're looking for a different option that would give you access to the events would be to implement your own popover directive that simply wraps bootstrap popovers. In theory, they can function the same as the ui-bootstrap and allows you to tap directly into the events provided by bootstrap.
HTML
<div my-popover="Hello World" popover-title="Title" popover-shown="myCallback()">...</div>
JavaScript ('my-popover.directive.js')
angular
.module('myModule')
.directive('myPopover', myPopover);
function myPopover() {
return {
scope: {
popoverTitle: '#',
popoverShown: '&'
},
restrict: 'A',
link: function(scope, elem, attr) {
$(elem).popover({
title: scope.popoverTitle,
content: attr.myPopover
});
$(elem).on('shown.bs.popover', function () {
if(scope.popoverShown && typeof scope.popoverShown === 'function'){
scope.popoverShown();
}
});
}
};
}
Similar to uib-popover, you can add support for additional configurations by adding additional scoped properties.

Scroll Bottom Angularjs Directive

I am working on chat app, and the problem seems to be that directive for scroll bottom, to the last item in ng-repeat is not working properly when there are images in messages.
So it just doesn't scroll all the way bottom.
I think the reason is that directive scrolls before the image is fully loaded.
// Scroll to bottom directive
.directive('schrollBottom', function ($timeout) {
return {
scope: {
schrollBottom: "="
},
link: function (scope, element) {
scope.$watchCollection('schrollBottom', function (newValue) {
if (newValue)
{
$timeout(function() {
$(element[0]).scrollTop($(element)[0].scrollHeight);
}, 0, false);
}
});
}
}
})
Check here to see how to wait for an image to load before doing something. You can add a class to all images and wait for all images with that class to load before scrolling.
I would keep what logic you have, and put it inside of an img.onload callback handler. Then any scrolling to the bottom will only occur once all images have loaded.

expand page element in a modal

I have a widget in the page that shows google chart for some data with couple of filters to filter the chart data and with a print icon to print it.
I want to add a button to open this same widget with the chart, filters and print functionality working in a modal with a larger screen view. because the widget is small in the page.
I have tried to add a button, and added a function for this button in the link function to open element.html() in a modal, the html worked but the issue is that the filters and the print are not functional .
What's wrong with element.html() ? I have tired to use $compile but it got me into many errors. what can I use?
app.directive("widget", function ($rootScope) {
return {
restrict: "EA",
scope: {
title: '=',
options: '='
},
transclude: true,
templateUrl: "widget.html",
link: function(scope, element, attrs, ctrl, transclude) {
scope.print = function() {....}
scope.filterChart = function() {....}
scope.expand = function() {
$rootScope.openModal("expand Modal", element.html(), {});
}
}
}
note that $rootScope.openModal is just a wrapper service that uses the $modal service, takes a title and a body
I think we have some issue with design.
To sort things out:
You have some logic (in your case "widget with the chart, filters and print functionality")
This logic should be implemented in directive or component (1.5+).
So directive name is widget like you did.
This directive you can implement in main page (what you did so far) or as part of modal. The modal is wrapper only for your widget. So create new emplty modal, put inside <widget title="xx" options=someOptions></widget> on you are fine
Since you have isolate scope directive I don't see any problem to make it work.

Mapbox map in ui-bootstrap tab not loading tiles

I'm trying to put a mapbox map inside an angular-ui-bootstrap tab, and it seems that some/most of the tiles are not getting loaded upon initialization, and are not being requested as you pan around on the map. Outside of the ui-bootstrap tabset, the maps work just fine.
No errors are being thrown, but looking at the requests for the tiles, many of them are just not being requested for some reason. I'm not even sure how to debug this one.
Any ideas as to what might be going on?
Here is a plunkr showing the issue
And here is an example angular app that will show the problem
var app = angular.module('app', ['ui.bootstrap'])
app.controller('mapCtrl', ['$scope', '$timeout', function($scope, $timeout) {
$scope.val = 123
}]);
app.directive('myMap', function() {
return {
restrict: 'E',
template: "<div id='map_container'></div>",
link: function ($scope, elem, attrs) {
mapDiv = elem.find('#map_container')
L.mapbox.accessToken = 'pk.eyJ1IjoicmVwdGlsaWN1cyIsImEiOiJlSWZtN1hZIn0.FfT3RxbfRYv4LIjBxXG5fw';
var map = L.mapbox.map(mapDiv[0], 'examples.map-i86nkdio')
.setView([40, -74.50], 9);
}
};
});
The map gets initialized when the mapcontainer is not visible, that's why it fails. You're on the right path with calling invalidateSize but you need to do that when the tab becomes visible. I see you've already setup an event which you could hook into in your directive link function:
$scope.$on('tabSelect:map', function (t) {
$timeout(function () {
map.invalidateSize(true);
});
});
It doesn't work without the timeout. It needs some sort of delay so the tab is complete visible before firing invalidateSize. Here's an updated Plunker: http://plnkr.co/edit/gzwx2pZ1GjBZDE8Utxfl?p=preview

How can I act on a html document once processed by angular?

I am relatively new to Angular.
I have a html document in which angular creates a html table with ng-repeat. When this table has been built, I would like to apply to it a Jquery function. How can I do that ?
function : $("#creneaux").footable()
If I apply the function in the controller when it is instantiated, nothing happens. when I apply it in the javascript console when the page has been displayed, it works.
Firstly, I would move the $("#creneaux").footable() into a directive.
Solution:
Use $timeout without a delay to (a bit simplified) put the action at the end of the browser event queue after the rending engine:
app.directive('tableCreator', function($timeout) {
return {
link: function(scope, element, attrs) {
$timeout(function() {
$("#creneaux").footable();
});
}
};
});
Demo: http://plnkr.co/edit/b05YKhipeVmrVHu2Xzsm?p=preview
Good to know:
Depending on what you need to perform, you can instead use $evalAsync:
app.directive('tableCreator', function($timeout) {
return {
link: function(scope, element, attrs) {
scope.$evalAsync(function() {
$("#creneaux").footable();
});
}
};
});
The difference is that now the code will run after the DOM has been manipulated by Angular, but before the browser re-renders.
This can in certain cases remove some flickering that might be apparent between the rendering and the call to for example the jQuery plugin when using $timeout.
In the case of FooTable, the plugin will run correctly, but the responsiveness will not kick in until the next repaint, since the correct dimensions are not available until after rendering.
Try writing a directive.
app.directive('sample', function() {
return {
restrict: 'EA',
link: function(scope, element, attrs) {
// your jquery code goes here.
},
};
});
Learn to write everything in angular instead jquery. This may help you "Thinking in AngularJS" if I have a jQuery background?

Resources