Angular. Execute a angular function from a popup window - angularjs

I have an angluar module.
In that module I have a controller with a function.
I need to execute that function in popup on href click.
As the popup content is not initially part of DOM or angular context, how can make a angular function to be executed by that generated code?
Here is what I try to code: codepen
app.controller('AppCtrl', ['$scope', 'myPopup', function($scope, myPopup) {
...
var infoWindow = new google.maps.InfoWindow({
content: "<a href='#' onclick='myPopup.show();'>this is my link</a>"
});
To retain is that I don't try to make execute exactly this code, I just search a way to execute an angular service function from a generated "on-fly" html code (a dynamic popup content, in my case).

First of all here's the working codepen: http://codepen.io/anon/pen/vKRWYy?editors=1010
So, the solution(just A solution. Not THE solution) is to add modal open function on window or global scope. And invoke that function on clicking the map.
window.showPopup = function(){
myPopup.show();
};
<a href='#' onclick='showPopup();return false;'>this is my link</a>
On a side note, it's generally not good practice to use non angular code with angular. It might be worth looking at an angular google maps implementation like: http://angular-ui.github.io/angular-google-maps/#!/. Maybe?

Related

Which pop up modal can be used in the app in which ui-router has been used

I have created a webpage in which different pages are opened through the Use of the UI-router different states for the each page opened and each page have may modules which are integrated through ng-include, Now I have the requirement of the popup modal needs to be integrated in my webpage but the pop modal doesnt work as expected Is their any popup modal which I can used in my webpage
I am using ngDialog and ui router. Here you can read:
Modals and popups provider for Angular.js applications. No
dependencies. Highly customizable.
Works like a charm.
On the documentation page you can see how to pass the scope or any other information you will need into the scope of the dialog to create the logic you need in your modal dialog. Taken from the documentation:
$scope.value = true;
ngDialog.open({
template: 'externalTemplate.html',
className: 'ngdialog-theme-plain',
scope: $scope
});
With a controller:
ngDialog.open({
template: 'externalTemplate.html',
scope: $scope
controller: ['$scope', 'otherService', function($scope, otherService) {
// controller logic
}]
});
In your scenario it is perhaps possible to use an ng-click on your link. Do some logic in the ng-click function and then open the ngDialog in this function with the appropriate data. Does that make sense? Or is it perhaps better to first open the dialog and use the passed data to do the needed data loading in the dialog itself. Perhaps a better user experience! ;)
You Can use the Angular Modal service to create a modal.
Please refer to the below link.
https://angular-ui.github.io/bootstrap/

How to make ui-sref work inside JQuery loaded HTML DOM

I am new to Angular JS. What I am doing is to bind ui-sref on JQuery loaded data.
All the JQuery plugins and rest of Angular is working perfectly fine. What I have for now looks like:
app.controller("FeedController", ['$scope', '$http', '$compile', function($scope, $http, $compile) {
var feed = this;
feed.years = [];
feed.getYears = function() {
$http.get('/timeline/years').success(function(data) {
feed.years = data;
});
};
feed.getYears();
$scope.$watch('sliderWrapper', function() {
applyTreemap(); // jquery treemap layout plugin
applyKnob(); // jquery knob plugin
});
// I was trying to compile externally loaded DOM by that plugin here.
// Didn't figure out how to do it.
$scope.refresh = function() {
// #slider is main content wrapper
$compile( $("#slider").html())($scope);
};
}]);
Please don't suggest to use AngularJS instead of JQuery. Actually this is a Treemap Layout plugin and already integrated into existing website.
Okay so $compile works as in my code but there are some problems I faced. Here's one. Consider the following code.
<div id="slider">
<div ng-repeat="slide in slides">
<!-- html loaded by jquery ajax will go here -->
</div>
</div>
In angular I was doing
$compile( $("#slider").html())($scope);
So, I was compiling html of #slider in angular and it already has angular bindings besides ajax loaded content. So angular compiler will re-render them and you will run into problems.
So keep in mind that you never $compile html that already has angular bindings.
So I solved my problem by putting
href="#/path/to/state"
instead of doing
ui-sref="home.child()"
into ajax loaded conent.
Sometimes you know something and its not in your mind when you are stuck. :-D

outside controller communication

How can a html element outside of a controller communicate with a given controller ?
The situation is as following:
<button name="search">Search</button> --> in an existing layout provided by an existing framework
<div ng-app ng-controller="overviewCtrl">
<div ng-view>/div> --> this one gets a specific controller
</div>
<button name="search">Search</button> --> in an existing layout provided by an existing framework
I don't have control on the location of the button outside of the controller.
I can put attributes on it and I want to put an ng-click attribute.
It also fall outside the ng-app.
I could put a controller on it. But then I need a way to have a reference to the same controller.
What is the best way to do this ?
One way to do this is to use JQuery inside the Angular controller to bind the element outside the ng-app to a scope function through JQuery selector and click event.
You don't have control over its position, but you do have control over its rendering in some way? You say you could put an ng-click on it?
I ask because there's an easy dodge here if that's true. You could make a simple directive that's basically a "smart ng-click". Your issue with ng-click is really that it's hard to route its call into your controller because the button is elsewhere. What you need, then, is just a way to bridge the two.
It would look something like this:
angular.module('myApp', [])
.controller('MyController', ['$scope', '$rootScope', function($scope, $rootScope) {
$rootScope.$on('SearchButtonClicked', function() {
// I will be called whenever the search button is clicked...
// and I am in my controller!
});
}])
.directive('notifySearchClick', ['$rootScope', function($rootScope) {
return {
restrict: 'A',
link: function($scope, iElement) {
iElement.bind('click', function() {
$rootScope.$emit('SearchButtonClicked');
});
}
};
}]);
Working Plunkr demonstrating this concept here:
http://plnkr.co/edit/dKuDl5?p=preview
The jQuery way is also perfectly valid but then you're back to the "what mystery event handlers are on THIS element" situation. It works, and it's reliable... but if you want to keep to the AngularJS philosophy, using a directive like the one above gives you a lot of flexibility.
Note that in the Plunkr reference above I added a tiny bit of sophistication. In that example I made the message name an attribute. You could thus use a single directive for any other cases like this in the future. Just put the message name into the attribute, like this:
<button notify-click="MyButtonNameClick"></button>

AngularJS load tabbed content directive dynamicly

I have a tabbed navigtion in my webapp that looks like this
Now I want to Change the directive each time the user clicks on one of the Navigation points. My Idea was to init the page with the first template.
$scope.currentDirective = $compile('<div order-Sale></div>');
Then when the user clicks on a tab, I wanted to change and compile the content again with a new directive in it. But for some reason this is not working. How would you proceed in order to archive this dynamic content loading? I really want to only load the content on necessary need and not just to show or hide it. I think using directives is the right way to go for it, but I'm a but stuck at the implementation... Someone any pointer ? (I don't want to use any jQuery)
What I tried [Edit]:
The controller.js
app.controller('pageController',['$scope','$compile', function($scope, $compile){
var templates = ['<div first-template></div>','<div second-template></div>'];
$scope.currentTemplate = $compile(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $compile(templates[id]);
};
}]);
The HTML
<div ng-controller="pageController">
<li>
<a ng-click="changeTemplate('1')">Change Template</a>
</li>
{{currentTemplate}}
</div>
UPDATE
$compile returns a linking function not a value, you cannot just bind it to your template with interpolation.
You should use ngBindHtml instead of regular bindings ( ngBind & {{ }} ).
ngBindHtml does compiling, linking and watching all out-of-the-box.
With ng-bind-html-unsafe removed, how do I inject HTML?
Here is a plunker
app.controller('pageController',['$scope','$compile','$sce', function($scope, $compile, $sce){
var templates = ['<div>first-template</div>','<div>second-template</div>'];
$scope.currentTemplate = $sce.trustAsHtml(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $sce.trustAsHtml(templates[id]);
};
}]);
The markup:
<div ng-controller="pageController">
<button ng-click="changeTemplate('1')">Change Template</button>
<div ng-bind-html="currentTemplate"></div>
</div>
For more robust dynamic content loading you have two good alternatives:
ngRoute from angular team.
ui-router from angular-ui team.
If you want to change and compile the content again, well that's exactly what ng-view/ ui-view directives already do for you.
Why not just use a directive:
You probably need to load a different template (html partial) for each tab.
You probably need to change the url based on the tab (and vice versa)
You probably need to instantiate a different controller for each tab.
ngRoute and ui-router come with their own directives.
You can implement your own route module if you want but that's more than just a directive.

angular.js link behaviour - disable deep linking for specific URLs

I have a working Angular.js app with HTML5 mode enabled.
$location.Html5mode(true).hashbang("!");
What I want to achieve is to get some URLs or <a> tags to do the normal browsing behaviour instead of changing the URL in the address bar using HTML5 history API and handling it using Angular controllers.
I have this links:
<a href='/auth/facebook'>Sign in with Facebook</a>
<a href='/auth/twitter'>Sign in with Twitter</a>
<a href='/auth/...'>Sign in with ...</a>
And I want the browser to redirect the user to /auth/... so the user will be then redirected to an authentication service.
Is there any way I can do this?
Adding target="_self" works in Angular 1.0.1:
<a target="_self" href='/auth/facebook'>Sign in with Facebook</a>
This feature is documented (https://docs.angularjs.org/guide/$location - search for '_self')
If you're curious, look at the angular source (line 5365 # v1.0.1). The click hijacking only happens if !elm.attr('target') is true.
An alternative to Fran6co's method is to disable the 'rewriteLinks' option in the $locationProvider:
$locationProvider.html5Mode({
enabled: true,
rewriteLinks: false
});
This will accomplish exactly the same thing as calling $rootElement.off('click'), but will not interfere with other javascript that handles click events on your app's root element.
See docs, and relevant source
This is the code for turning off deep linking all together. It disables the click event handler from the rootElement.
angular.module('myApp', [])
.run(['$location', '$rootElement', function ($location, $rootElement) {
$rootElement.off('click');
}]);
To work off the Nik's answer, if you have lots of links and don't want to add targets to each one of them, you can use a directive:
Module.directive('a', function () {
return {
restrict: 'E',
link: function(scope, element, attrs) {
element.attr("target", "_self");
}
};
});
I've run into the same issue a few times now with angular, and while I've come up with two functional solutions, both feel like hacks and not very "angular".
Hack #1:
Bind a window.location refresh to the link's click event.
<a
href=/external/link.html
onclick="window.location = 'http://example.com/external/link.html';"
>
The downside and problems with this approach are fairly obvious.
Hack #2
Setup Angular $routes that perform a $window.location change.
// Route
.when('/external', {
templateUrl: 'path/to/dummy/template',
controller: 'external'
})
// Controller
.controller('external', ['$window', function ($window) {
$window.location = 'http://www.google.com';
}])
I imagine that you could extend this using $routeParams or query strings to have one controller handle all "external" links.
As I said, neither of these solutions are very satisfactory, but if you must get this working in the short term, they might help.
On a side note, I would really like to see Angular support rel=external for this type of functionality, much like jQueryMobile uses it to disable ajax page loading.
To add to Dragonfly's answer, a best practice I have found to limit the number of target="_self" attributes is to never put the ng-app attribute on the body tag. By doing that you are telling angular that everything within the body tags are a part of the angular app.
If you are working within a static wrapper that should not be affected by angular, put your ng-app attribute on a div (or other element) that surrounds only the location your angular app is going to be working in. This way you will only have to put the target='_self' attribute on links that will be children of the ng-app element.
<body>
... top markup ...
<div ng-app="myApp">
<div ng-view></div>
</div>
... bottom markup ...
</body>
In your routes try:
$routeProvider.otherwise({})

Resources