how to access function in factory outside controller - angularjs

<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
firstname:<input type="text" ng-model="data.firstName">
lastname:<input type="text" ng-model="data.lastName">
<br>name is : <strong>{{data.firstName}} {{data.lastName}}</strong>
</div>
<div ng-controller="SecondCtrl">
name in 2nd controller: {{data.firstName}} {{data.lastName}}
<button ng-click="updateData('kv','a')">click</button>
</div>
<button onclick = "ChangeEvn()"/>
</div>
<script>
var myApp = angular.module("myApp", []);
myApp.factory('MyService', function(){
return {
data: {
firstName: '',
lastName: ''
},
update: function(first, last) {
this.data.firstName = first;
this.data.lastName = last;
}
};
});
myApp.controller('FirstCtrl', function($scope, MyService){
$scope.data = MyService.data;
});
myApp.controller('SecondCtrl', function($scope, MyService){
$scope.data = MyService.data;
$scope.updateData = function(first, last) {
MyService.update(first, last);
}
});
function ChangeEvn()
{
alert("Ok");
myApp.factory.update("Hello", ".....");//doesn't work
}
</script>
</body>
</html>
In the above code value is passed between two controllers using factory .Now i want to update first name and lastname using button click. button click function is outside the controller(i require that) . Now how to access the update outside controller myApp.factory.update("Hello", "....."); this statement doesn't work

Please read the Angular documentation of services:
To use an Angular service, you add it as a dependency for the component (controller, service, filter or directive) that depends on the service. Angular's dependency injection subsystem takes care of the rest.
You are trying to access the service method outside of an angular component. That is not at all recommended, if possible at all. If you are using angular, try to do everything "inside Angular subsystem". Trying to bypass the angular context will only cause problems, and it's not needed at all.
If you want to use a service method, then create a MainController, inject the service in it, attach the controller to some HTML element, and put your update button as a child of that element.
<body>
<div ng-app="myApp">
<div ng-controller="MainCtrl">
<button onclick="updateData('FirstName', 'LastName')" />
</div>
</div>
<script>
var myApp = angular.module("myApp", []);
myApp.factory('MyService', function () {
return {
data: {
firstName: '',
lastName: ''
},
update: function (first, last) {
this.data.firstName = first;
this.data.lastName = last;
}
};
});
myApp.controller('MainCtrl', function($scope, MyService) {
$scope.updateData = MyService.update;
});
</script>
</body>

Related

How to create directives elements programmatically?

Angular 1.4.8
How can I create directive elements programmatically inside a controller? I tried $compile but it doesn't work for me.
Controller and directive
angular.module('plunker', [])
.controller('MainCtrl', function ($scope, $compile) {
var container = angular.element(document.getElementById('container'));
$scope.user = {item: 'Axe'};
var item = angular.element(document.createElement('anItem'));
item = $compile(item)($scope);
container.append(item);
})
.directive('anItem', function(){
return {
templateUrl: 'template.html'
};
});
template.html
<p>Item: {{user.item}}</p>
index.html
...
<body ng-controller="MainCtrl">
<div id="container"></div>
</body>
...
Here is my plunker: http://plnkr.co/edit/XY6C6J70PjQTrjiwjHSz?p=preview
While the name of the directive is "anItem", the DOM elements are named "an-item". This is just the Angular naming convention. This works:
document.createElement('an-item')
Here is the updated Plunker.
var elm = angular.element('<an-item"></an-item>');
container.append(elm);
scope.$applyAsync(function () {
$compile(elm)(scope);
});

How can compile scope ngClick in directive on ngRepeat

I have a directive, in this directive we compile ngRepeat as you see.
my problem is :
I can't call $scope.delete() from controller, and i don't know how can compile it in my directive.
Note: run the sample
var app = angular.module("app", []);
app.controller("ctrl", function ($scope, $http) {
var root = "http://jsonplaceholder.typicode.com";
$scope.list = [];
$http.get(root + "/users").success(function (data) {
$scope.list = data;
});
///i can't call this scope
$scope.delete = function (item) {
alert("delete called");
}
});
app.directive("mydata", ["$compile", "$filter", function ($compile, $filter) {
return {
restrict: "A",
scope: {
list: "="
},
link: function (scope, element) {
var ngRepeat = element.find(".repeat").attr("ng-repeat", "item in list");
$compile(ngRepeat)(scope);
}
}
}]);
<!DOCTYPE html>
<html ng-app="app" ng-controller="ctrl">
<head>
<title></title>
</head>
<body>
<ul id="parent" mydata data-list="list">
<li class="repeat">
{{item.name}}
<button ng-click="delete()">delete</button>
</li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>
Don't know why u are trying to do stuffs like this but a quick solution for your code is to compile the ngRepeat with the controller's scope instead of the directive the scope;
$compile(ngRepeat)(scope.$parent);
Your delete() won't fire since u are creating an isolated scope on your my-data directive. The delete() method will not get inherited.
For more conception about isolated scope and scope inheritance, check https://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive and https://docs.angularjs.org/guide/scope

angularjs click event inside the ngBindHtml directive

I have an angularjs sample code snippet here where i can bind the html tags using ng-bind-html directive. But how can I include some other tags like angularjs ng-click, id tag etc inside ngBindHtml directive like
Test
My sample code is here:
var app = angular.module("myApp", ['ngSanitize']);
app.controller("myCtrl", function($scope) {
$scope.myText = "<a href='#' ng-click='someFunction()'>Test</a>";
$scope.someFunction = function(){
alert("Link Clicked");
};
});
FYI, the data is loaded dynamically from server side script and i have to use ng-bind-html inside ng-repeat directive and i have to pass respective id's to click events something like ng-click="myFunction(x.id)" as in sample 2.
As suggested #Dr Jones, you need use $compile directive.
Live example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope) {
$scope.myText = "<button ng-click='someFunction(1)'>{{text}}</button>";
$scope.text = "Test";
$scope.someFunction = function(val) {
console.log(val);
};
})
.directive('bindHtmlCompile', function($compile) {
return {
restrict: "A",
scope: {
bindHtmlCompile: "="
},
link: function(scope, elem) {
scope.$watch("bindHtmlCompile", function(newVal) {
elem.html('');
var newElem = angular.element(newVal);
var compileNewElem = $compile(newElem)(scope.$parent);
elem.append(compileNewElem);
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<h3>
Write code for test button
</h3>
<textarea cols="100" ng-model="myText"></textarea>
<div bind-html-compile="myText">
</div>
</div>
</div>

Insert directive into the DOM using jqlite

I need to use jqlite to insert the HTML for the directive, but for some reason the directive does not insert the template.
<div ng-app="docsSimpleDirective">
<div ng-controller="Controller">
<button ng-click="showCustomer($event)">click to see the customer</button>
<div>
</div>
And my app.js looks like:
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function ($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
$scope.showCustomer = function($event) {
angular.element($event.currentTarget).next().html("<div my-customer></div>");
};
}])
.directive('myCustomer', function () {
return {
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
http://jsfiddle.net/4nad43gn/
NOTE: This is just to try and recreate the situation i'm in, but the directive has to be inserted to the DOM in a similar way to the above - otherwise it will not work for my situation.
As Michelem mention the best way to do DOM manipulation is using directive.
If you still want to do this by using controller you can take a look at my example: http://jsfiddle.net/4nad43gn/3/
$scope.showCustomer = function($event) {
var element = document.querySelectorAll('[ng-controller=Controller] div');
var tpl = $compile( "<div my-customer=''></div>" )( $scope );
element[0].appendChild(tpl[0]);
};
You need to add $compile in your application. It's possible?
Don't know why you did that but this is more simple:
JSFiddle
HTML:
<div ng-app="docsSimpleDirective">
<div ng-controller="Controller">
<button ng-click="showCustomer = true">click to see the customer</button>
<div my-customer ng-show="showCustomer"></div>
</div>
</div>
JS:
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function ($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
$scope.showCustomer = false;
}])
.directive('myCustomer', function () {
return {
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
PS
you can also use ng-ifinstead ng-show if you don't want to have the element (instead only hidden) before the click.

How do you use $sce.trustAsHtml(string) to replicate ng-bind-html-unsafe in Angular 1.2+

ng-bind-html-unsafe was removed in Angular 1.2
I'm trying to implement something where I need to use ng-bind-html-unsafe. In the docs and on the github commit they say:
ng-bind-html provides ng-html-bind-unsafe like behavior (innerHTML's the result without
sanitization) when bound to the result of $sce.trustAsHtml(string).
How do you do this?
Filter
app.filter('unsafe', function($sce) { return $sce.trustAsHtml; });
Usage
<ANY ng-bind-html="value | unsafe"></ANY>
That should be:
<div ng-bind-html="trustedHtml"></div>
plus in your controller:
$scope.html = '<ul><li>render me please</li></ul>';
$scope.trustedHtml = $sce.trustAsHtml($scope.html);
instead of old syntax, where you could reference $scope.html variable directly:
<div ng-bind-html-unsafe="html"></div>
As several commenters pointed out, $sce has to be injected in the controller, otherwise you will get $sce undefined error.
var myApp = angular.module('myApp',[]);
myApp.controller('MyController', ['$sce', function($sce) {
// ... [your code]
}]);
Personally I sanitize all my data with some PHP libraries before going into the database so there's no need for another XSS filter for me.
From AngularJS 1.0.8
directives.directive('ngBindHtmlUnsafe', [function() {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
element.html(value || '');
});
}
}]);
To use:
<div ng-bind-html-unsafe="group.description"></div>
To disable $sce:
app.config(['$sceProvider', function($sceProvider) {
$sceProvider.enabled(false);
}]);
var line = "<label onclick="alert(1)">aaa</label>";
1. use filter
app.filter('unsafe', function($sce) { return $sce.trustAsHtml; });
using (html):
<span ng-bind-html="line | unsafe"></span>
==>click `aaa` show alert box
2. use ngSanitize : safer
include angular-sanitize.js
<script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
add ngSanitize in root angular app
var app = angular.module("app", ["ngSanitize"]);
using (html):
<span ng-bind-html="line"></span>
==>click `aaa` nothing happen
Simply creating a filter will do the trick. (Answered for Angular 1.6)
.filter('trustHtml', [
'$sce',
function($sce) {
return function(value) {
return $sce.trustAs('html', value);
}
}
]);
And use this as follow in the html.
<h2 ng-bind-html="someScopeValue | trustHtml"></h2>
If you want the old directive back, you can add this to your app:
Directive:
directives.directive('ngBindHtmlUnsafe', ['$sce', function($sce){
return {
scope: {
ngBindHtmlUnsafe: '=',
},
template: "<div ng-bind-html='trustedHtml'></div>",
link: function($scope, iElm, iAttrs, controller) {
$scope.updateView = function() {
$scope.trustedHtml = $sce.trustAsHtml($scope.ngBindHtmlUnsafe);
}
$scope.$watch('ngBindHtmlUnsafe', function(newVal, oldVal) {
$scope.updateView(newVal);
});
}
};
}]);
Usage
<div ng-bind-html-unsafe="group.description"></div>
Source - https://github.com/angular-ui/bootstrap/issues/813
JavaScript
$scope.get_pre = function(x) {
return $sce.trustAsHtml(x);
};
HTML
<pre ng-bind-html="get_pre(html)"></pre>
For Rails (at least in my case) if you are using the angularjs-rails gem, please remember to add the sanitize module
//= require angular
//= require angular-sanitize
And then load it up in your app...
var myDummyApp = angular.module('myDummyApp', ['ngSanitize']);
Then you can do the following:
On the template:
%span{"ng-bind-html"=>"phone_with_break(x)"}
And eventually:
$scope.phone_with_break = function (x) {
if (x.phone != "") {
return x.phone + "<br>";
}
return '';
}
my helpful code for others(just one aspx to do text area post)::
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication45.WebForm1" %>
<!DOCTYPE html>
enter code here
<html ng-app="htmldoc" xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="angular.min.js"></script>
<script src="angular-sanitize.min.js"></script>
<script>
angular.module('htmldoc', ['ngSanitize']).controller('x', function ($scope, $sce) {
//$scope.htmlContent = '<script> (function () { location = \"http://moneycontrol.com\"; } )()<\/script> In last valid content';
$scope.htmlContent = '';
$scope.withoutSanitize = function () {
return $sce.getTrustedHtml($scope.htmlContent);
};
$scope.postMessage = function () {
var ValidContent = $sce.trustAsHtml($scope.htmlContent);
//your ajax call here
};
});
</script>
</head>
<body>
<form id="form1" runat="server">
Example to show posting valid content to server with two way binding
<div ng-controller="x">
<p ng-bind-html="htmlContent"></p>
<textarea ng-model="htmlContent" ng-trim="false"></textarea>
<button ng-click="postMessage()">Send</button>
</div>
</form>
</body>
</html>
$scope.trustAsHtml=function(scope)
{
return $sce.trustAsHtml(scope);
}
<p class="card-text w-100" ng-bind-html="trustAsHtml(note.redoq_csd_product_lead_note)"></p>

Resources