Render angular's html from the variable on scope - javascript

I'm aware of security implications related to my request, but I need to allow a special super admin group of users an ability to create and evaluate angular html contained within variable on current $scope
Here is an example plunk:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl" ng-init="variable = 3; content = '{{ variable }}'">
<div>
The value of $scope.variable === "{{ variable }}"
</div>
<div>
The value of $scope.content === "{{ content }}"
</div>
<br>
<div>
The value of $scope.content is <b>ng-model</b>'ed via the following textarea:<br>
</div>
<textarea rows="3" ng-model="content"></textarea>
<div style="border: 1px solid black">
Instead of rendering the value of the $scope.content field which is currently equal to "{{ content }}" I need to render compiled and evaluated value which should be equal to "{{ variable }}"
</div>
</body>
</html>
Any suggestions?
Thank you in advance!

You can make a directive that uses the $compile service to do this for you.
Here is what I came up with, and a fork of your Plunkr to show that it works.
app.directive('compile', function($compile) {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
var prevScope;
scope.$watch(attrs.compile, function(newVal, oldVal) {
// create a span (an inline element) so we have an actual DOM node to
// set the innerHTML of.
var newElem = document.createElement('span');
newElem.innerHTML = newVal;
// clean up first
if (prevScope) {
prevScope.$destroy();
prevScope = null;
}
// clear out the contents of this element
elem.empty();
// and replace it with the raw (uncompiled) node
elem[0].appendChild(newElem);
// now the node is in the DOM so we can compile it
// but we want to use a try..catch because the user
// might be in the middle of typing a new expression,
// but the syntax right now is not valid so the
// expression parser will throw an error.
try {
// compile the node in the DOM with a child of the existing scope
prevScope = scope.$new();
$compile(newElem)(prevScope);
} catch (e) { /* don't need to do anything here */ }
});
}
}
});

Related

Style text with innerText while still escaping HTML

I want to dynamically set the text of a p element with styling, but I do not know how to do this.
Here is my HTML element: <p id="delete-speaker-info-message"> </p>
Here is my current code to set the text:
document.getElementById("delete-speaker-info-message").innerHTML = `Are you sure you want to delete <b>${speakerName}</b> from <b>${eventName}</b>? This cannot be undone.`
Although the code above works, the speakerName, and eventName values are user inputted and need to be escaped. I know innerText can do this but it also escapes the bold tags. I am sure there is a way to do this but I just could not find it online. Thanks for the help!
Your best bet is to use a templating library. If you try to roll your own, you're probably going to mess it up and end up with XSS vulnerabilities. There's always a hacker out there who will think of something you haven't. Using a library also lets you do nice things like have an html template and pass in variables to be safely interpolated into it.
It sounds like you're not using any of the larger frameworks like React or Angular, so I'd say Lodash's template function is your best bet. Here's an example from their docs:
// Use the HTML "escape" delimiter to escape data property values.
var compiled = _.template('<b><%- value %></b>');
compiled({ 'value': '<script>' });
// => '<b><script></b>'
You should use something like my special function:
//<![CDATA[
/* external.js */
var doc, bod, I, special, unspecial; // for use on other loads
addEventListener('load', function(){
doc = document; bod = doc.body;
I = function(id){
return doc.getElementById(id);
}
special = function(str){
return str.replace(/&/g, '&').replace(/'/g, '&apos;').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
}
unspecial = function(str){
return str.replace(/&/g, '&').replace(/&apos;/g, "'").replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
}
var speakerName = '<i>Cool Joe</i>', eventName = '<div>Keeping it Real</div>';
var deleteSpeakerInfoMsg = I('delete-speaker-info-message');
deleteSpeakerInfoMsg.innerHTML = 'Are you sure you want to delete <b>'+special(speakerName)+'</b> from <b>'+special(eventName)+'</b>? This cannot be undone.';
console.log(deleteSpeakerInfoMsg.innerHTML);
}); // end load
//]]>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1' />
<title>Test Template</title>
<link type='text/css' rel='stylesheet' href='external.css' />
<script type='text/javascript' src='external.js'></script>
</head>
<body>
<div id='delete-speaker-info-message'></div>
</body>
</html>

How to call a sibling scope in angular js using rootscope

Here is my app.js
var app = angular.module("app",[]);
app.controller("myFirstController",['$scope',function($scope){
$scope.test = "myfirstName";
$scope.test1 = "myfirstName";
}])
app.controller("mySecondController",['$scope','$rootScope',function($scope,$rootScope){
$scope.test = "myLastName";
//Here how to call my test,test1 scope using $rootScope ??
}])
Can i do this using $rootScope?I dont want to use any emit and broadcast or this
if you store any value in rootscope like :
$rootScope.test =" value ";
and you can retrieve value from the rootScope like
var value = $rootScope.test;
But it's not good to use for data maintenance and security
because if you refresh browser, then all scope values are cleared.
So I will suggest you for 3 varies ways
$cookies
$ngStorage
$Service
Broadcast
I dont want to use any emit and broadcast or
But that's the only way is best to pass value from one controller to another controller
you can do like below but use different names for avoiding errors in some cases.if you doesn't declare it as $rootScope in first ctrl then it will be undef in second ctrl
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
<script src="app.js"></script>
</head>
<body >
<div ng-controller="myFirstController">
</div>
<div ng-controller="mySecondController">
</div>
</body>
<script>
var app = angular.module('plunker', []);
app.controller("myFirstController",['$scope','$rootScope',function($scope,$rootScope){
$rootScope.test = "myfirstName";
}])
app.controller("mySecondController",['$scope','$rootScope',function($scope,$rootScope){
$scope.test = "myLastName";
console.log($rootScope.test);
//Here how to call my myFirstName scope using $rootScope ??
}])
</script>
</html>

Create javascript element and link to angluarjs

I am using button to create element in javascript DOM way as follows
var app = angular.module('app', []);
function createElement2(resource){
el= document.createElement('textarea');
$(el).attr('ID', "Textbox0");
$(el).attr('type', "text");
$(el).attr('value', "Textbox0");
$(el).attr("name","Textbox0");
$(el).attr("ng-model", "html");
//this line will be diffrent for element
document.getElementById("areaT").appendChild(el)
}
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
console.log("test")
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
function MyController($scope) {
$scope.click = function(arg) {
alert('Clicked ' + arg);
}
$scope.html = '<a ng-click="click(1)" href="#">Click me</a>';
}
The problem is I want to a tag customize directive Angluarjs to any element create with different validtion and the dirctive code execute only when the page load.In another words I want to execute the next piece of code every time I create element
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.0.7" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
</head>
<body>
<h1>Compile dynamic HTML</h1>
<div id="areaT" ng-controller="MyController">
<textarea ng-model="html"></textarea>
<div dynamic="html"></div>
</div>
<input type="button" onclick="createElement2(this)">
</body>
</html>
note that the textarea in the html code when enter any code the console.log("test") and so on will be execute. what I need when click on button the textarea that will be adding execute what the textarea in the html code execute (console.log("test") and so) when enter text inside it

Display input value with Ng-Model referenced

I am aware that I cannot set the value of an input when Ng-Nodel is referenced, but I am trying to find a work around.
The html value is being pulled from the URL variable (such as full name or email) that the user has entered in the previous page. Ng-model is being used to store these information. - signUp.php?user_email=$email&fname=$fullNam
Below is an example of what I mean,
<?php
$email = $_GET['user_email'];
$fullName = $_GET['fname'];
?>
<input id="signupformItem" ng-model="user.username" type="email" name="email" value= <?php echo $email; ?> placeholder="Email Address" required> <br>
Any help would be greatly appreciated
I just created a demo for you but I will recommend you to go through some series of tutorial to get better knowledge of the framework or technology(angularjs and javascript) you are going to use in your project.
I created plunk for you. You can visit it here.
Javascript code
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, userService) {
$scope.name = 'World';
$scope.userName = userService.getUsers();
userService.getUserAjax()
.success(function(response) {$scope.names = response[0].Name;});
});
app.service('userService', function($http){
var fac = {};
fac.getUserAjax = function() {
return $http.get("http://www.w3schools.com//website/Customers_JSON.php");
};
fac.getUsers = function(){ return 'John'};
return fac;
});
HTML code
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.13/angular.js" data-semver="1.3.13"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
by {{userName}}
<p>username loaded by ajax :{{names}}</p>
</body>
</html>
You need to define one service that communicate to your web page using ajax service provided by angular ($http) and call it from the controller and on the success function just pick up the value and assign it to your scope variable. In your case username.
I just used w3schools service url here just for demonstration which would give me a list of users you need to implement php code that would return what you want and use it like described above.
I hope it would have given you basic idea of how to setup angular code to communicate to the server.

template in directive doesn't appear

I'm new to AngularJS and am learning directives. I used the tutorials from egghead.io and am stuck with the following example:
<html>
<head lang="en">
<script type = "text/javascript" src = "../libs/angular/angular.js" ></script >
<script type = "text/javascript" src = "example.js" ></script>
</head>
<body>
<div ng-app="phoneApp">
<div ng-controller="phoneCtrl">
<phoneDir></phoneDir>
</div>
</div>
</body>
</html>
example.js contains this:
var app = angular.module('phoneApp',[]);
app.controller('phoneCtrl',function($scope) {
});
app.directive('phoneDir',function() {
return {
restrict:"E",
template:'<div> Panel </div>'
}
})
Its a very simple example that's just trying to use a directive in the HTML The problem is I don't see the div having the 'Panel' defined in the template. Can someone help?
directives use camelCase name only in the code, markup uses hyphenated names
use
<phone-dir>
Try adding the replace: true property. I think that will solve your issue.
app.directive('phoneDir',function() {
return {
restrict:"E",
replace: true,
template:'<div> Panel </div>'
}
})

Categories