AngularJS - How can I create a new, isolated scope programmatically?

AngularjsAngularjs Scope

Angularjs Problem Overview


I want to create an AlertFactory with Angular.factory. I defined an html template like follow

var template = "<h1>{{title}}</h1>";

Title is provided by calling controller and applied as follow

var compiled = $compile(template)(scope);
body.append(compiled);

So, how I can pass isolated scope from controller to factory? I'm using in controller follow code

AlertFactory.open($scope);

But $scope is global controller scope variable. I just want pass a small scope for factory with just title property.

Thank you.

Angularjs Solutions


Solution 1 - Angularjs

You can create a new scope manually.

You can create a new scope from $rootScope if you inject it, or just from your controller scope - this shouldn't matter as you'll be making it isolated.

var alertScope = $scope.$new(true);
alertScope.title = 'Hello';

AlertFactory.open(alertScope);

The key here is passing true to $new, which accepts one parameter for isolate, which avoids inheriting scope from the parent.

More information can be found at: http://docs.angularjs.org/api/ng.$rootScope.Scope#$new

Solution 2 - Angularjs

If you only need to interpolate things, use the $interpolate service instead of $compile, and then you won't need a scope:

myApp.factory('myService', function($interpolate) {
    var template = "<h1>{{title}}</h1>";
    var interpolateFn = $interpolate(template);
    return {
        open: function(title) {
            var html = interpolateFn({ title: title });
            console.log(html);
            // append the html somewhere
        }
    }
});

Test controller:

function MyCtrl($scope, myService) {
    myService.open('The Title');
}

Fiddle

Solution 3 - Angularjs

Followings are the steps:

  1. Add your HTML to the DOM by using var comiledHTML = angular.element(yourHTML);
  2. Create a new Scope if you want var newScope = $rootScope.$new();
  3. Call $comile(); function which returns link function var linkFun = $compile(comiledHTML);
  4. Bind the new scope by calling linkFun var finalTemplate = linkFun(newScope);
  5. Append finalTemplate to your DOM YourHTMLElemet.append(finalTemplate);

Solution 4 - Angularjs

check out my plunkr. I'm programmatically generating a widget directive with a render directive.

https://plnkr.co/edit/5T642U9AiPr6fJthbVpD?p=preview

angular
  .module('app', [])
  .controller('mainCtrl', $scope => $scope.x = 'test')
  .directive('widget', widget)
  .directive('render', render)

function widget() {
  return {
    template: '<div><input ng-model="stuff"/>I say {{stuff}}</div>'
  }
}

function render($compile) {
  return {
    template: '<button ng-click="add()">{{name}}</button><hr/>',
    link: linkFn
  }

  function linkFn(scope, elem, attr) {
    scope.name = 'Add Widget';
    scope.add = () => {
      const newScope = scope.$new(true);
      newScope.export = (data) => alert(data);
      const templ = '<div>' +
                      '<widget></widget>' +
                      '<button ng-click="export(this.stuff)">Export</button>' +
                    '</div>';
      const compiledTempl = $compile(templ)(newScope);
      elem.append(compiledTempl);
    }
  }
}

Solution 5 - Angularjs

I assume when you are talking about an isolate scope you are talking about a directive.

Here is an example of how to do it. http://jsfiddle.net/rgaskill/PYhGb/

var app = angular.module('test',[]);

app.controller('TestCtrl', function ($scope) {
    $scope.val = 'World';
});

app.factory('AlertFactory', function () {

    return {
        doWork: function(scope) {
            scope.title = 'Fun';    
            //scope.title = scope.val;  //notice val doesn't exist in this scope
        }
    };

});

app.controller('DirCtrl', function ($scope, AlertFactory) {
    AlertFactory.doWork($scope);  
});

app.directive('titleVal',function () {
    return {
        template: '<h1>Hello {{title}}</h1>',
        restrict: 'E',
        controller: 'DirCtrl',
        scope: {
            title: '='
        },
        link: function() {
    
        }
    };

});

Basically, attach a controller to a directive that has defined an isolate scope. The scope injected into the directive controller will be an isolate scope. In the directive controller you can inject your AlertFactory with wich you can pass the isolate scope to.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPremierView Question on Stackoverflow
Solution 1 - AngularjsAlex OsbornView Answer on Stackoverflow
Solution 2 - AngularjsMark RajcokView Answer on Stackoverflow
Solution 3 - AngularjsAmit Prabhu ParrikarView Answer on Stackoverflow
Solution 4 - AngularjsRichard LinView Answer on Stackoverflow
Solution 5 - AngularjsrgaskillView Answer on Stackoverflow