AngularJS showing html scope as raw text - angularjs

i'm using an API to get my posts of my blog. But i'm getting the content that's a HTML code but i'm trying to see it as i saw in the blog but aren't working.
I had tried it using this filter and functions:
.filter('unsafe', function($sce) {
return function(val) {
return $sce.trustAsHtml(val);
};
})
And in controller:
function htmlDecode(input){
var e = document.createElement('div');
e.innerHTML = input;
return e.childNodes[0].nodeValue;
}
In the template:
<div ng-bind-html="post.conteudo | unsafe"></div>
But this codes aren't making this work properly. As result of this, i get a raw/plain text like this:
What can i do?

You are overcomplicating things. You don't need this filter, as well as htmlDecode function. All you need is $sce.trustAsHtml:
$scope.post.conteudo = $sce.trustAsHtml('<b>Thomas Mann</b>');
and in HTML:
<div ng-bind-html="post.conteudo"></div>
angular.module('demo', []).controller('DemoController', function($scope, $sce) {
$scope.post = {}
$scope.post.conteudo = $sce.trustAsHtml('<b>Thomas Mann</b>')
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoController">
<div ng-bind-html="post.conteudo"></div>
</div>

Related

ionic + anguular ng-bind-html is not working

I have fetched json webservice one of its field contain HTML tags
actually web service has < & > my code looks like
angular.module('starter.controllers', ['ionic','ngSanitize'])
.controller('DashCtrl', function($scope) {})
.controller('DetailCtrl', ['$sce','$scope', '$stateParams','Chats',function($sce,$scope, $stateParams, Chats) {
$scope.exe = Chats.detail($stateParams.exeId,$stateParams.sub_exeId);
$scope.renderHtml = function(html_code)
{
return $sce.trustAsHtml(html_code);
};
}])
//also tried the following filter
.filter('to_trusted', ['$sce', function($sce){
return function(text) {
return $sce.trustAsHtml(text);
};
}])
at my view I tried the following variations
<p ng-bind-html="exe.tips.replace('<','<').replace('>','>') | to_trusted"></p>
<p ng-bind-html="exe.tips | to_trusted"></p>
<p ng-bind-html="exe.tips"></p>
<p ng-bind-html="renderHtml(exe.tips)"></p>
and tried many other thing but still getting rendered the HTML
at view source it is like this <p>"<ol><li>text</li>....

AngularJS: ng-repeat track by obj.id doesn't reinitialise transcluded content when obj.id changes

function ComponentController() {
var vm = this;
this.$onInit = function() {
vm.link = 'http://example.com/obj/' + vm.obj.id;
}
}
function MainController($scope, $timeout) {
$scope.arrObjs = [{id: 1, name: "object1"},{id: 2, name: "object2"}];
console.log('object1\'s id is ', $scope.arrObjs[0].id);
$timeout(function() { // simulates a call to server that updates the id
$scope.arrObjs[0].id = '3';
console.log('object1\'s new id is ', $scope.arrObjs[0].id, '. Expected the link above to be updated with the new ID');
}, 1000);
}
var someComponent = {
bindings: {
obj: '='
},
template: '<div>URL: <span>{{$ctrl.link}}</span></div>',
controller: ComponentController
};
angular.module('myApp', []);
angular
.module('myApp')
.controller('MainController', MainController)
.controller('ComponentController', ComponentController)
.component('someComponent', someComponent);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MainController">
<div ng-repeat="obj in arrObjs track by obj.id">
<some-component obj="obj"></some-component>
</div>
</div>
</div>
After the ng-repeat and its someComponent are rendered one of the objects' obj.id changes (using a $timeout in the above example). The vm.link for that object still carries the old id!
Now, I know that the $onInit() is only run once inside someComponent, but why doesn't track by re-initialise the component because the obj.id changed?
If Angular truly tracked an array by the obj.ids, it should treat an obj whose id changes as a completely different object and re-initialise it, no?
Obviously a $watch on vm.obj.id within someComponent will fix it, but is there a way without adding yet another $watch?
NOTE: previously I was using
<div ng-repeat="objID in vm.arrObjIDs track by objID" ng-init="obj = vm.fnLookUpObjByID(objID)">
<someComponent obj="obj"></someComponent>
</div>
And that works perfectly! This is exactly how I expected the track by obj.id to work. But I'm trying to move away from the ng-init pattern.
You're missing something somewhere in your code that you're not showing us.
The following snippet works.
init() is not a standard function though. You probably mean $onInit()
function ComponentController() {
var vm = this;
console.log("not in init: " + this.obj.id);
this.$onInit = function() {
console.log("in init: " + vm.obj.id);
}
}
function MainController($scope) {
$scope.arrObjs = [{id: 1, name: "object1"},{id: 2, name: "object2"}];
}
var someComponent = {
bindings: {
obj: '='
},
template: '<div>ID: <span>{{$ctrl.obj.id}}</span></div>',
controller: ComponentController
};
angular.module('myApp', []);
angular
.module('myApp')
.controller('MainController', MainController)
.controller('ComponentController', ComponentController)
.component('someComponent', someComponent);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MainController">
<div ng-repeat="obj in arrObjs track by obj.id">
<some-component obj="obj"></some-component>
</div>
</div>
</div>
EDIT:
If you add an asynchronous function in the middle, the compiling of the code will always be faster than the return of the async function.
Using $watch is the standard way of updating the view when data changes.
There's not other way.
Note: With components you can use $onChanges() but in this particular case it won't trigger since you have to change the reference of the object for it to update. $onChanges() calls $watch in any case.

passing ng-show between two different controllers

I have a button which falls into Controller B and two block of HTML code which kind of falls under controller A...............and button falls into one block of HTML code
Example:
<div ng-controller="A">
<div ng-show="now">
<div>
<Button ng-controller="B"></Button>
</div>
</div>
<div ng-show="later">
</div>
</div>
On one button click I show up now block and later on button click of B controller I kind of hide now block and display later block.
How do I achieve this functionality?? I am not able to pass ng-show varibales between two different controller files......what should I use???
Hope this helps...!
angular.module('app', [])
.controller('A', function($scope) {
console.log('A');
$scope.state = {
now: true
};
$scope.showLater = function() {
$scope.state.later = true;
};
})
.controller('B', function($scope) {
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="A" ng-app="app">
<div ng-show="state.now">
<div>
<button ng-controller="B" ng-click="showLater()">Show Later</button>
</div>
</div>
<div ng-show="state.later">LATER
</div>
<p> <pre ng-bind="state | json"></pre>
</p>
</div>
You could use a simple service that stores the state.
Example:
angular.module('mymodule').service('ActiveService', function() {
var service = {};
var status = false;
service.getStatus = function() {
return status;
}
service.toggle = function() {
status = !status;
}
return service;
})
And in your controller:
angular.module('mymodule').controller('SomeController', function(ActiveService) {
$scope.status = ActiveService.getStatus;
})
The Angularjs service is a singelton, so it will hold your values for you across different controllers, directives or pages.
Could also be used directly:
// Controller
$scope.service = ActiveService;
// Html
<div ng-show="service.getStatus()">
...
</div>
You can also achieve this by declaring the variable in $rootScope and watching it in controller A,
app.controller('A', function($scope, $rootScope) {
$rootScope.now = true;
$rootScope.later = false;
$rootScope.$watch("now", function() {
$scope.now = $rootScope.now;
$scope.later = !$rootScope.now;
})
});
In Controller B, you just change the value of now based on previous value like this on ng-click,
app.controller('B', function($scope, $rootScope) {
$scope.testBtn = function() {
$rootScope.now = !$rootScope.now;
}
});
I have implemented a button within different divs(now and later) in a plunker,
http://embed.plnkr.co/xtegii1vCqTxHO7sUNBU/preview
Hope this helps!

store key in a variable for each ng-repeat

I am fairly new to angular js.
I have two different scope data in my controller ($scope.itemdata & $scope.skudata, both are simplified in the plucker). Both are guaranteed to have the same structure for any key.
I have a nested ng-repeat for item data and I want to store/keep a track of keys inside each ng-repeat so that I can use the path variable to get the value out of skudata.
Problem: {{path}} expression in HTML is not resolving to correct key value.
Looking at the console log the keys are added and removed in the correct order.
I am not sure where I am going wrong.
Here is plucker : http://plnkr.co/edit/0q8tZ9JLsGdfR03YbpYB?p=info
HTML Code:<body ng-controller="MainCtrl">
<p>Hello</p>
<script type="text/ng-template" id="field_renderer.html">
<div ng-init="addkeyToPath(key)"></div>
{{key}}
{{value}}
<!--output should be skudata.value but instead its skudata-->
{{path}}
<div ng-init="removeKeyFromPath(key)"></div>
{{path}}
</script>
<div>
<div ng-repeat="(key ,value) in itemData" ng-include="'field_renderer.html'"></div>
</div>
Controller Code:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.path = 'skudata';
$scope.isThisAnObject = function(input) {
return angular.isObject(input) ? true : false;
}
$scope.addkeyToPath = function(input) {
console.log("Adding");
console.log($scope.path);
$scope.path = $scope.path + "." + input;
console.log($scope.path);
};
$scope.removeKeyFromPath = function(input) {
console.log("remove");
console.log($scope.path);
$scope.path = $scope.path.substring(0,$scope.path.lastIndexOf("."));
console.log($scope.path);
};
$scope.itemData =
{ value:'item_name',
length:'10'
};
$scope.skudata =
{ value:'sku_name',
length:'20'
};
});
The problem is that you're using the $scope path variable, when really you want to display path variable of the item itself. Make a few changes to get this working plunkr
Template:
<div ng-init="addkeyToPath(this, key)">
{{key}}: {{value}}
{{path}}
</div>
Controller:
$scope.addkeyToPath = function(item, input) {
item.path = $scope.path + "." + input;
};
$scope.itemData = {
value:'item_name',
length:'10'
};

Working with two modules in AngularJS

I have two modules with different operations and I tried to work with them as shown below.
<div id="viewBodyDiv" ng-app="xhr">
<div ng-controller="xhrCtrl">
<button ng-click="callAction()">Click</button>
{{sample}}
</div>
</div>
<div id="viewBodyDiv2" ng-app="xhr2">
<div ng-controller="xhr2Ctrl">
<button ng-click="alertMessage()">Click</button>
</div>
</div>
The JS is shown below.
angular.module('xhr', []).controller('xhrCtrl', function ($http, $scope, $window) {
$scope.sample = "sadf";
$scope.callAction = function () {
$http({
method: 'GET',
url: 'Angular/GetData',
params: {
api_key: 'abc'
}
}).then(function (obj) { //I get a text result that I display near the button
$scope.sample = obj.data;
});
};
});
angular.module('xhr2', []).controller('xhr2Ctrl', ['$window','$scope',
function ($window,$scope) {
$scope.alertMessage = function () {
$window.alert("xhr2Ctrl clicked");
};
}]);
When I click on the viewBodyDiv I am getting the desired output but when I click on viewBodyDiv2 the alert message is not getting displayed.
I am new to AngularJS and please let me know what I am doing wrong or what it the procedure to work with two different Modules in Angular.
Thank you.
add this code to the bottom of your JavaScript
angular.element(document).ready(function() {
angular.bootstrap(document.getElementById('viewBodyDiv2'),['xhr2']);
});
Hope this helps.
As per the AngularJS documentation:
https://docs.angularjs.org/api/ng/directive/ngApp
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application.
However, if you still want to do it this way, you have to use angular.boostrap() manually to achieve this. Here is a good tutorial on this:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
So you need to bootstrap the module to have multiple angular apps on the same page.
You can also inject one of the modules into another.
var xhrModule = angular.module("xhr", ["xhr2"]);
Following is a sample code for bootstrapping the module.
<html>
<head>
<script src="angular.min.js"></script>
</head>
<body>
<div id="viewBodyDiv" ng-app="xhr">
<div ng-controller="xhrCtrl">
<button ng-click="callAction()">Click</button>
{{sample}}
</div>
</div>
<div id="viewBodyDiv2" ng-app="xhr2">
<div ng-controller="xhr2Ctrl">
<button ng-click="alertMessage()">Click</button>
</div>
</div>
<script>
var xhrModule = angular.module("xhr", []);
xhrModule.controller('xhrCtrl', function ($http, $scope, $window) {
$scope.sample = "sadf";
$scope.callAction = function () {
$http({
method: 'GET',
url: 'Angular/GetData',
params: {
api_key: 'abc'
}
}).then(function (obj) { //I get a text result that I display near the button
$scope.sample = obj.data;
});
};
});
var xhr2Module = angular.module("xhr2", [])
xhr2Module.controller('xhr2Ctrl', ['$window','$scope',
function ($window,$scope) {
$scope.alertMessage = function () {
$window.alert("xhr2Ctrl clicked");
};
}]);
angular.bootstrap(document.getElementById("viewBodyDiv2"),['xhr2']);
</script>

Resources