Calling angularjs scope function from href
Asked Answered
M

7

10

I am using a library which appends a href element onto an tag. On this link I need to make a call to an angularjs function that is within scope. Something like...

<a href="{{someFunction()}}"></a>

Note: I am attaching this href via javascript from another library (nvd3.js) not actually writing this in because if I was I could easily use ng-click or ng-href.

Mcclain answered 8/1, 2014 at 17:0 Comment(0)
V
14

That's a bit convoluted.

CAVEAT: This is very, very hacky and just absolutely exactly what you're NOT supposed to do in angular, but I guess you know that and the library is making your life hard...

First, unlike onclick, an href won't interpret a string as javascript. Instead, you'd have to use

<a href="javascript:someFunction()"></a>

But this alone won't make it work, because someFunction() is not a method on the document, but on the controller, so we need to get the controller first:

<a href="javascript:angular.element(
         document.getElementById('myController')).scope().someFunction();"></a>

Where myController refers to the DOM element that is decorated with ng-controller, e.g.

<div data-ng-controller="SomeController" id="myController"> ... </div>

If someFunction modifies the state of the view, you'll also need to use $scope.apply, i.e.

<a href="javascript:angular.element(document.getElementById('myController')).
           scope().$apply(someFunction)"></a>

Note that you don't need the {{ }} syntax, because you're calling javascript directly, you're not asking angular to modify your markup.

Valgus answered 8/1, 2014 at 17:51 Comment(3)
The most beautiful hack I have seen. Works like a charm!Mcclain
I thought it was working but jumped the gun: This is definitely the right track. Here is what I tried:angular.element('directive-name').scope().loadUsers(1); And the error said angular.element(...).scope(...).loadUsers is not a function. When I type angular.element('directive-name') it returns the proper object with the scope() function on it.Mcclain
Ok figured out I have to be on the $$childHead object first like so... angular.element("directive-name").scope().$$childHead and it works!Mcclain
W
19

So I was not pleased with the answer to this as it doesn't really utilize an elegant angular solution.

Here's my solution: http://jsfiddle.net/jjosef/XwZ93

HTML:

<body class="wrapper" ng-app="ExampleApp">
  <a my-href="buildUrl('one', aVariable, 'three')">This is my a tag with a function that builds the url</a>
</body>

JS:

angular.module('ExampleApp', []);
angular.module('ExampleApp').run(function($rootScope) {
  $rootScope.buildUrl = function() {
    var link = [];
    for(var i = 0; i < arguments.length; i++) {
      link.push(arguments[i].toLowerCase());
    }
    return '/#!/' + link.join('/');
  };

  $rootScope.aVariable = 'two';
});

angular.module('ExampleApp').directive('myHref', function($parse) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var url = $parse(attrs.myHref)(scope);
      element.attr('href', url);
    }
  }
});
Wittenburg answered 1/7, 2014 at 13:26 Comment(3)
this should be the top answer :/Hileman
You could you also use scope.$eval instead of $parse to avoid the need for dependency injection. See modified jsfiddle.Tying
this code will not work if minified. see modified jsfiddle which will work with minification.Aerugo
V
14

That's a bit convoluted.

CAVEAT: This is very, very hacky and just absolutely exactly what you're NOT supposed to do in angular, but I guess you know that and the library is making your life hard...

First, unlike onclick, an href won't interpret a string as javascript. Instead, you'd have to use

<a href="javascript:someFunction()"></a>

But this alone won't make it work, because someFunction() is not a method on the document, but on the controller, so we need to get the controller first:

<a href="javascript:angular.element(
         document.getElementById('myController')).scope().someFunction();"></a>

Where myController refers to the DOM element that is decorated with ng-controller, e.g.

<div data-ng-controller="SomeController" id="myController"> ... </div>

If someFunction modifies the state of the view, you'll also need to use $scope.apply, i.e.

<a href="javascript:angular.element(document.getElementById('myController')).
           scope().$apply(someFunction)"></a>

Note that you don't need the {{ }} syntax, because you're calling javascript directly, you're not asking angular to modify your markup.

Valgus answered 8/1, 2014 at 17:51 Comment(3)
The most beautiful hack I have seen. Works like a charm!Mcclain
I thought it was working but jumped the gun: This is definitely the right track. Here is what I tried:angular.element('directive-name').scope().loadUsers(1); And the error said angular.element(...).scope(...).loadUsers is not a function. When I type angular.element('directive-name') it returns the proper object with the scope() function on it.Mcclain
Ok figured out I have to be on the $$childHead object first like so... angular.element("directive-name").scope().$$childHead and it works!Mcclain
D
9

You should probably use ng-click here.

Dictograph answered 9/6, 2014 at 18:32 Comment(1)
The problem with ng-click is it would only detect clicks and not when the user navigates to the element with the Tab key and then press Space. In other words, the click event is not semantic.Narrative
L
2

The simplest solution is

<a href="" ng-click="someFunction(x,y,z)">Go</a>

href="" is important, otherwise hover cursor style does not change to a pointer

Loathing answered 6/10, 2015 at 22:7 Comment(1)
See my comment above, ng-click handles the click DOM event, which is not semantic: it detects clicks but it doesn't detect when the user navigates to the element with the Tab key and then presses Space.Narrative
R
1

I mixed some things here and I have it working.

I have a menu with some options, each one calls a different method on the controller.

<span ng-show="hoverOptions" ng-mouseleave="hoverOut()" class="qk-select ui-select-container qk-select--div">
    <ul>
        <li ng-repeat="option in menuOptions"><a href="javascript:void(0);" ng-click="callFunction(option.action)">{{option.name}}</a></li>
    </ul>
</span>

The callFunction method in the controller is defined like that:

$scope.callFunction = function (name){
      if(angular.isFunction($scope[name]))
                $scope[name]();
}

And the menu options are defined also in the controller in that way:

$scope.menuOptions = [{action: "uploadPhoto" , name:"Cargar foto"}, {action: "logout", name:"Cerrar sesión"}, {action: "createUser", name:"Nuevo usuario"}];

Hope it helps someone.

Rillings answered 22/9, 2016 at 17:39 Comment(0)
W
0

You'll need to use $parse() to process the tag when using {{someFn}}.

Wilderness answered 8/1, 2014 at 17:22 Comment(0)
B
0

solution: https://embed.plnkr.co/bhMcEO/

<!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8" />
      <title>$window or $location to Redirect URL in AngularJS</title>
      <link rel="stylesheet" href="style.css" />
      <script src="https://code.angularjs.org/1.4.1/angular.js"></script>
      <script>
        var app = angular.module('RedirectURLApp', []);
        app.controller('RedirectURLCtrl', function($scope, $window) {
          $scope.name = 'Anil';
          $scope.RedirectToURL = function() {
            var host = $window.location.host;
            var landingUrl = "http://www.google.com";
            alert(landingUrl);
            $window.location.href = landingUrl;
          };
        });
      </script>
    </head>
    <body ng-app="RedirectURLApp">
      <div ng-controller="RedirectURLCtrl">
        <h2>$window or $location to Redirect URL in AngularJS</h2>
        <p>Hello {{name}},</p>
        Click to Redirect <a href="" ng-click="RedirectToURL()">Click Me!</a>
      </div>
      <div><h4><a href="http://www.code-sample.com/2015/06/redirect-to-new-page-using-location-or.html">For more detail..</a></h4></div>
    </body>
    </html>
Bakeman answered 8/10, 2018 at 15:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.