angular leaflet custom markers (using angular directives) - angularjs

I'm trying to create a "leaflet marker" using an angular directive. For design purposes, we separate the presentation and the model so different persons can work on different parts of the application. My issue, more likely, is more a "scope" problem than a "leaflet" problem. I'm trying to pass an object to be used in the angular directive, while I'm adding the markers on "$scope", in the controller. That directive, "" in my app, is the only tag in my "message" property on each marker object to be presented in the map. It has an attribute "estacao" which in portuguese is the same as "station".
So, my code is here:
angular.forEach($scope.estacoes, function(estacao) {
$scope.markers.push({
lat: estacao.latitude,
lng: estacao.longitude,
message: "<popup estacao='estacoes[" + i + "]'></popup>"
});
i++;
});
http://plnkr.co/edit/evaQpqGZUz39Y7MNqbo7?p=preview
The problem seams to be that my "estacao" is null when the directive is processed.
Can anyone help me to figure out what is happening?

The 'auto' compile of the popup message (from the leaflet directive) uses the root scope.
So you need to assign your response estacoes to the root scope:
promiseEstacoes.then(function(estacoes) {
$rootScope.estacoes = estacoes.estacoes;
...
}
http://plnkr.co/edit/OkQcth2zNrEdO2rgwBv8?p=preview

With the latest versions of angular-leaflet-directive, you can specify a scope to use on message rendering:
$scope.markers.push({
lat: estacao.latitude,
lng: estacao.longitude,
getMessageScope: function() { return $scope; }
message: "<popup estacao='estacoes[" + i + "]'></popup>"
});

Related

Is there an equivalent in Angular JS of props from React JS?

I am learning angularJS and I was wondering if there is the equivalent of props like there is in react. More specifically, a way to add with props that I define in another file. It would make the website I'm coding in angular much more efficient but I can't find the equivalent in Angular.
There is a way to do something similar in AngularJS. It is called Directives. In your case you want to create a directive with restrict set to 'E'.
'E' tells the compiler that it will be an element in the generated HTML.
angular.module('scopeDirective', [])
.controller('app', ['$scope', function($scope) {
$scope.naomi = { name: 'Uriel', address: '1600 Amphitheatre' };
$scope.igor = { name: 'Bitton', address: '123 Somewhere' };
}])
.directive('customer', function() {
return {
restrict: 'E',
scope: {
customerInfo: '=info'
},
templateUrl: 'customer.html'
};
});
The scope object after restrict defines the various attributes you would want this directive to accept. This is similar to how props work in React. In that object, you can see customerInfo which corresponds to the directive's isolate scope property. The value (=info) tells $compile to bind to the info attribute.
The templateUrl maps to the HTML for this directive.
Using the above directive will look something like below:
<div ng-controller="app">
<customer info="uriel"></customer>
<hr>
<customer info="bitton"></customer>
</div>
Kindly refer to the AngularJS docs on Directives.
NOTE: Instead of trying to do something in AngularJS that is similar to how you do things in React or any other framework/library, I would suggest you do not instead embrace the current framework's capability and use it as is without trying to compare way of achieving similar things as this can lead to frustration down the road.
I hope you find this answer useful for your needs.
Is it not the same as using #Input() info:string in the component and when its being used
<component [info] = "string">
?
in react it would be {props.info} in the component
and then <component info="something"> when its being used

Add event handler to DOM element that is created after a $resource get (AngularJS)

I'm having a hard time enabling a Bootstrap's popover component to my dom elements.
I'm working with AngularJS and on my template, I am using the ng-repeat directive to create a gallery.
<div ng-repeat="phone in phones" >
<a class="thumb" href="#/phones/{{phone.id}}">
<img class="img-responsive phone_image" ng-src="{{phone.image_path}}" data-content="{{phone.text}}" rel="popover" data-placement="right" data-trigger="hover">
</a>
</div>
On my template controller, I'm fetching the phones data from a third party API and than injecting it to the scopes variable "phones", like so:
phoneControllers.controller('PhoneListCtrl', ['$scope', 'Phones',
function ($scope, Cards) {
// Phones is the service that queries the phone data to the API
Phones.query(function(data){
// Got a response, add received to the phones variable
$scope.phones = data;
// for each .card_image element,give it the popover property
$('.phone_image').popover({
'trigger': 'hover'
});
});
}]
);
My problem lies with the $('.phone_image').popover segment. My thought was that by doing it inside the query's callback function it would work, since that's when the ".phone_image" elements are created. However it doesn't.
I seem to be failing to understand exactly in what scope should I assign the .popover property. I know it works because if I do it on the developer tools console, after all page content has been loaded, it works properly. I just don't know where to call it in my code to begin with.
Thanks in advance
It's happening because you are manipulating the DOM inside a controller. You should not do this, as the documentation says:
Do not use controllers to:
Manipulate DOM — Controllers should contain only business logic. Putting any presentation logic into Controllers significantly affects its testability. Angular has databinding for most cases and directives to encapsulate manual DOM manipulation.
In other words, when you use an Angular controller, you're just delegating the DOM manipulation to Angular through $scope databinding.
If you would like to manipulate the DOM, you should rely on directives. In your case, you can create a phonePopover directive like this:
angular
.module('phone', [])
.directive('phonePopover', function() {
return {
restrict: 'A',
replace: false,
scope: {
phoneText: '=phonePopover'
},
link: function(scope, element, attr) {
element.popover({
'trigger': 'hover',
'placement': 'right',
'content': scope.phoneText
});
}
});
And apply it to your element as following:
<img data-phone-popover="{{phone.text}}" class="img-responsive phone_image" ng-src="{{phone.image_path}}">

Using angular-translate on a template loaded asynchronously

I am using angular-translate on an app. It uses tabs that can switch its contents dynamically with the help of angular-ui, I get the content through a custom service that uses $http.
The template is then sanitised and pushed into an array for later rendering:
var addNewTab = function(template, tabClass) {
var id = $scope.tabs.length + 1;
tabClass = tabClass || '';
template = $sce.trustAsHtml(template);
template = $compile(template)($scope);
$scope.tabs.push({
id: id,
name: 'PLACEHOLDER TITLE',
active: true,
content: template,
tabClass: tabClass
});
};
In the view it is rendered with {{tab.content}}, everything up to this point works quite well, the problem I have is getting angular-translate to translate the newly inserted template.
Inside the template I am using the translate directive to translate things but since the template is outside the $scope of wherever translations happen, its texts are not being rendered.
I thought I could get it to work using $compile but I don't quite get how to use it.
Any ideas would be greatly appreciated.

Google maps for AngularJS

I am very new to AngularJS and I am trying to use https://github.com/angular-ui/angular-google-maps.
I am just trying to get the map to render on my page but I am getting an error message and I don't know what it means. Any help with understanding this error message would be appreciated.
I've created a plunk here:
github.com/twdean/plunk
Here is the Error in the browser:
Error: [$compile:multidir] Multiple directives [googleMap, markers] asking for new/isolated scope on: <google-map center="center" draggable="true" zoom="zoom" markers="markers" mark-click="true" style="height: 400px">
http://errors.angularjs.org/1.2.3/$compile/multidir?p0=googleMap&p1=markers&p2=new%2Fisolated%20scope&p3=%3Cgoogle-map%20center%3D%22center%22%20draggable%3D%22true%22%20zoom%3D%2
I suggest another alternative, ng-map.
I created a google maps angularjs directive called, ng-map, for my own project. This does not require any Javascript coding for simple functionality.
To Get Started
One. Download and include ng-map.js or ng-map.min.js
<script src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script src="dist/ng-map.min.js"></script>`
Two. use map tag, and optionally, control, marker, and shape tags
<ng-map zoom="11" center="[40.74, -74.18]">
<marker position="[40.74, -74.18]" />
<shape name="circle" radius="400" center="[40.74,-74.18]" radius="4000" />
<control name="overviewMap" opened="true" />
</ng-map>`
Examples
To use it in your app, simply include 'ngMap' as dependency to your app.
var myApp = angular.module('myApp', ['ngMap']);
Hope it helps
-------------- EDIT -------------------
For those who looks for angular2 version,
there is also ng2-map https://ng2-ui.github.io/#/google-map
It seems that you're including a "markers" attribute within your google-map element.
Indeed as #Tyler Eich mentions, the docs as of Dec 5, 2013 remain outdated. Removing the marker attribute seems to make it work.
Here is how to display markers:
index.html
<div ng-controller="MapCtrl">
<google-map id="mymap"
center="center"
zoom="zoom"
draggable="true"
mark-click="false">
<markers>
<marker ng-repeat="marker in markers" coords="marker">
</marker>
</markers>
</google-map>
</div>
controller.js
var controller = module.controller('MapCtrl', function($scope) {
$scope.myMarkers = [
{
"latitude":33.22,
"longitude":35.33
},
...
];
$scope.center = {
latitude: 33.895497,
longitude: 35.480347,
};
$scope.zoom = 13;
$scope.markers = $scope.myMarkers;
$scope.fit = true;
});
I have just today had a need to implement a google map into my angular application. Since my implementation required something quite simple I decided to do this myself and create a simple directive. I will leave my source below for anyone who might find it usefull.
Create a directive
Create HTML
Optionally pass the coordinates through directive/controller if
you need.
DIRECTIVE
angular.module('ngPortalApp')
.directive('googleMap', function () {
return {
template: '<iframe width="100%" height="350" frameborder="0" style="border:0"></iframe>',
restrict: 'E',
scope: {
pbcode: '='
},
link: function postLink(scope, element) {
var mapFrame = element.find("iframe");
if (scope.pbcode) {
mapFrame.attr('src', "https://www.google.com/maps/embed?pb=" + scope.pbcode);
}
else {
mapFrame.attr('src', '');
}
}
};
});
HTML
<div class="col-lg-12">
<google-map pbcode="'!1m0!3m2!1sen!2srs!4v1445332712674!6m8!1m7!1s34JkuBgIzmIJNmpFNThuUg!2m2!1d40.75816449978445!2d-73.98911289129973!3f175.51693470959802!4f7.069842517148402!5f0.7820865974627469'"></google-map>
</div>
Thats all there is to it. Remember that the google query string is called "pb" this is the code used in all embed codes you can grab from google. You may pass this to your directive straight up or if you need to via your controller or even through the directive itself. You can set any iframe map settings in the directive within the template.
To change between Street View or Map View you just send the corresponding code whichever source you are getting them from (db, json, etc).
For the above example:
Street Code:
!1m0!3m2!1sen!2srs!4v1445332712674!6m8!1m7!1s34JkuBgIzmIJNmpFNThuUg!2m2!1d40.75816449978445!2d-73.98911289129973!3f175.51693470959802!4f7.069842517148402!5f0.7820865974627469
Map Code:
!1m18!1m12!1m3!1d755.5452773113641!2d-73.98946157079955!3d40.75804119870795!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0000000000000000%3A0x1952a6258d36ecc5!2sMcDonald's!5e0!3m2!1sen!2srs!4v1445332854795
Haven't had any issues with this as yet.
Here's a fiddle: jsFiddle
If you want to include markers you should do that in another element inside the google-maps directive.
You should do something like:
<google-maps options="someOptionsObject">
<markers cords="someArrayWithLatitudeAndLongitudeCords"></markers>
</google-maps>
For Angular2, there is angular2-google-maps. License as of 2016-05-14: MIT.

AngularJS: 'google-maps': call directive in infoWindow

I'm using http://nlaplante.github.io/angular-google-maps/ to display a map in my angular Application.
I have a general controller for my page getting a Json.
to display markers, i'm using $watch in the scope cause I will do real time and the markers positions can change.
$scope.model = new Model 'api/now.json'
$scope.state = new DState
$scope.$watch ->
markers = []
_($scope.model.objects).each (obj) ->
markers.push
latitude: obj.latitude
longitude: obj.longitude
infoWindow: "<info-window>SHOULD NOT DISPLAY CAUSE DIRECTIVE</info-window>"
markers
, (newValue) ->
$scope.state.map.markers = newValue
, true
My directive is basic:
am.directive "infoWindow", ->
restrict: 'E'
template: "<div>IN DIRECTIVE</div>"
replace: true
My Html page calling the map:
#dashboard{ng:{controller: 'dashboardCtrl'}}
#map.google-map{center: 'state.map.center',
zoom: 'state.map.zoom',
markers: 'state.map.markers',
draggable: 'true'}
And The DState Factory to define the state:
.factory 'DashboardState', (Media) ->
class DashboardState
defaults:
map:
center:
latitude: 45.764043
longitude: 4.835659
zoom: 10
markers: []
selectedObj: null
constructor: (initialData) ->
_(#defaults).extend initialData
_(this).extend #defaults
So, my display here in my infoWindow is
SHOULD NOT DISPLAY CAUSE DIRECTIVE
But I should have what is in my directive:
IN DIRECTIVE
My directive is not called ... Do you have an idea?
It's a double question here, I would like to set the SelectedObj of my factory to the Obj himself. Do you have an Idea how to handle the event click on marker and where to place it to call the method who could assign my obj to SelectedObj?
Thanks by advance
You can try the following:
get the latest version of angularjs-ui-maps
Use the tempalteUrl property of the directive - you can add your directives inside the template (see how this is done in the example.html that's included in the source).
This way you can avoid any custom compilation of html
I'd faced a similar problem: https://stackoverflow.com/questions/20843463/angularjs-using-a-directive-in-google-maps-marker-window
In case you find any other approach, please do post it.
HTH

Resources