Angular sce.trustAsHtml not working - angularjs

I have this angular controller :
var applicaton = angular.module("appUsed", ['ui.router','ngSanitize'] );
applicaton.controller('gamesController', ['$scope','$http','$sce','$stateParams',function(scope,http,sce,stateParams){
http.get('/'+stateParams.category+'/'+stateParams.id)
.success(function(result){
scope.Game = result.gameDetails;
scope.relatedGames = result.relatedGames;
console.log(scope.Game.title);
console.log(scope.Game.url);
scope.gameUrl = sce.trustAsHtml('<iframe allowfullscreen width="80%" height="600px src="'+scope.Game.url+'"></iframe>');
});
}]);
and this html :
<div class="game_and_description">
<div ng-bind-html="gameUrl"></div>
<h3> Description</h3>
<p> {{Game.description}}</p>
It shows me a white iframe. I searched over the internet and i've done everything right. The modules form angular ng-sanitize is running(called from <script> tag) and i have no error. the console log on scopes works like a charm. Don't know where should i look anymore. Please help.

You need to give a trust to the URL you are using in the iframe, and compile the html:
<div ng-controller="gamesController">
<div bind-html-compile="gameFrame"></div>
</div>
var myApp = angular
.module('appUsed',['ngSanitize'])
.controller('gamesController', ['$scope', '$sce', function (scope, sce) {
scope.Game = {
url: 'https://play.famobi.com/hop-dont-stop/A-DXC93'
};
scope.gameUrl = sce.trustAsResourceUrl(scope.Game.url);
scope.gameFrame = sce.trustAsHtml('<iframe allowfullscreen width="80%" height="600px" ng-src="{{gameUrl}}"></iframe>');
}])
.directive('bindHtmlCompile', ['$compile', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(function () {
return scope.$eval(attrs.bindHtmlCompile);
}, function (value) {
element.html(value && value.toString());
var compileScope = scope;
if (attrs.bindHtmlScope) {
compileScope = scope.$eval(attrs.bindHtmlScope);
}
$compile(element.contents())(compileScope);
});
}
};
}]);
See https://github.com/incuna/angular-bind-html-compile.
The working fiddle: http://jsfiddle.net/masa671/k2e43nvf/

I had a similar problem. I solved it like this :
my view :
<div ng-bind-html="getDescription()"></div>
my controller :
$scope.getDescription = function () {
if ($scope.description != null && $scope.todo.description.length > 0) {
return $sce.trustAsHtml($scope.description);
} else {
return 'no description.';
}
};

Related

AngularJS - view not updated when directive changes data in service

I'm using a directive to interact with a service and am encountering some trouble with the view showing the latest data.
I setup the following example. You can see that when a controller interacts with the Service, the view will update with the latest data. If you click the directive link, you can see in the console the data was changed but the view is not updated with that data.
http://jsfiddle.net/kisonay/pv8towqc/
What am I missing?
JavaScript:
var app = angular.module('myApp', []);
app.factory('Service', function() {
var Service = {};
Service.data = {};
Service.data.active = false;
Service.data.one = {};
Service.data.many = [];
Service.changeActive = function(state) {
state = state || false;
Service.data.active = state;
};
Service.setOne = function(one) {
Service.data.one = one;
};
Service.setMany = function(many) {
Service.data.many = many;
};
return Service;
});
app.directive('launcher', function(Service) {
return {
restrict: "A",
link: function(scope, elem, attrs) {
elem.bind('click', function(event) {
if (Service.data.active) {
Service.changeActive(false);
} else {
Service.changeActive(true);
}
console.log(Service.data); // shows data changed
});
}
};
});
function Ctrl1($scope, Service) {
$scope.ServiceData = Service.data;
}
function Ctrl2($scope, Service) {
$scope.active = function() {
Service.changeActive(true);
};
$scope.inactive = function() {
Service.changeActive(false);
};
}
HTML
<div ng-controller="Ctrl1">
{{ServiceData}}
</div>
<hr />
<div ng-controller="Ctrl2">
Directive: <a href="#" launcher>Change</a>
<hr /> Controller:
<button ng-click="active()">
Active
</button>
<button ng-click="inactive()">
Inactive
</button>
</div>
Your event listener executes but Angular doesn't know anything about it, so it doesn't know it has to detect changes.
Add scope.$apply(); at the evn of the click listener, and it will work as expected.
app.directive('launcher', function(Service) {
return {
restrict: "A",
link: function(scope, elem, attrs) {
elem.bind('click', function(event) {
scope.$apply(function() {
if (Service.data.active) {
Service.changeActive(false);
} else {
Service.changeActive(true);
}
});
});
}
};
});

AngularJS :wait in 'link' of directive is not working

In the below source, the watch method in the link part of a custom directive is not working. I use 'link' within the directive because I have to update the DOM structure.
How can I get the watch in the link{} of the directive working EACH time the button is pushed?
EDIT: I found the wrong code. See below 'ERROR' and 'CORRECT' code.
The HTML above this script is (click on a button to increment a variable):
<div ng-controller="AppController as vmx">
<button ng-click="vmx.incrementFoo()">Increment Foo</button>:
{{ vmx.fooCount }}.
<div foo-count-updated></div>
</div>
Angular code:
angular.module( "myapp", [])
.controller( "AppController", myAppController)
.directive('showAlsoInCustomDirective', showAlsoInCustomDirective);
// *** CONTROLLER
function myAppController( $scope ) {
var vm = this;
vm.fooCount = 0;
vm.copiedFooCount = 0;
// ERROR code:
// **vm.getFooCount** = function() {
// return vm.fooCount;
// }
// CORRECT code:
getFooCount = function() {
return vm.fooCount;
}
vm.getFooCount = getFooCount;
vm.incrementFoo = incrementFoo;
function incrementFoo() {
++vm.fooCount;
}
}
// *** DIRECTIVE
.directive('fooCountUpdated', fooCountUpdater);
function fooCountUpdater() {
var indirectivecounter = 0;
getFooCountInDirective = function() {
return getFooCount();
}
var watcherFn = function (watchScope) {
return getFooCountInDirective();
}
return {
link: function (scope, element, attrs) {
scope.$watch(watcherFn, function (newValue, oldValue) {
element.html( "Got the change: " + newValue);
})
}};
}
The complete source is put in this file:
https://plnkr.co/edit/J6nfLQ3dmLW0gDNXV0J5?p=preview
As indicated above, the solution was simple. It is also in the plunker file.
HTML:
<div ng-controller="AppController as vmx">
<button ng-click="vmx.incrementFoo()">Increment Foo</button>:
{{ vmx.fooCount }}.
<div foo-count-updated></div>
</div>
Angular code:
angular.module( "myapp", [])
.controller( "AppController", function( $scope ) {
var vm = this;
vm.fooCount = 0;
getFooCount = function() {
return vm.fooCount;
}
vm.getFooCount = getFooCount;
vm.incrementFoo = incrementFoo;
function incrementFoo() {
++vm.fooCount;
}
})
.directive('fooCountUpdated', fooCountUpdater);
function fooCountUpdater() {
var indirectivecounter = 0;
getFooCountInDirective = function() {
return getFooCount();
}
var watcherFn = function (watchScope) {
return getFooCountInDirective();
}
return {
link: function (scope, element, attrs) {
scope.$watch(watcherFn, function (newValue, oldValue) {
element.html( "Got the change: " + newValue);
})
}};
}

Flickity carousel: Items pushed out of viewport with ng-repeat?

Im trying to use metafizzy's flickity framework to display content dynamically, using angulars ng-repeat.
But for some reason the items seem to get pushed out from the flickity-viewport when loaded onto the DOM. Anyone know why that happens and how to avoid it?
The gallery works fine When displaying static content inside it like this;
HTML : STATIC MARKUP EXAMPLE
<div ng-controller="FlickityCtrl">
<div id="main-content" class="gallery js-gallery">
<div class="gallery-cell"> Static Title </div>
<div class="gallery-cell"> Static Title </div>
<div class="gallery-cell"> Static Title </div>
</div>
..its When trying to populate the gallery with the help of angular's ng-repeat directive,that the gallery breaks.
HTML : MARKUP USING NG-REPEAT
<div ng-controller="FlickityCtrl" >
<div id="main-content" class="gallery js-gallery">
<div ng-repeat="chapter in chapters" ng-click="loadSubchapters(chapter.title)">
<h1 class="gallery-cell cell-card-bg">
{{ chapter.title | strip_namespace }}
</h1>
</div>
</div>
<hr>
<button ng-click="loadChapters()" >Load chapters</button>
<hr>
<ul>
<li ng-repeat="chapter in subchapters">
{{ chapter.title | strip_namespace }}
</li>
</ul><br />
<hr >
</div>
JAVASCRIPT
angular.module('FlickityApp', [])
.controller('flickityCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
var updateUI = function(data) {
if (!data || !data.query) { return; }
$timeout(function() {
$scope.chapters = data.query.pages;
console.log(data);
});
};
$scope.loadChapters = function() {
mw.loader.using('mediawiki.api', function() {
(new mw.Api()).get({
action: 'query',
generator: 'categorymembers',
gcmtitle: 'Category:examplepage'
}).done(function(data) {
$timeout(function() {
$scope.chapters = data && data.query ? data.query.pages : {};
});
});
});
};
$scope.loadSubchapters = function(chapterTitle) {
mw.loader.using('mediawiki.api', function() {
(new mw.Api()).get({
action: 'query',
generator: 'categorymembers',
gcmtitle: chapterTitle
}).done(function(data) {
$timeout(function() {
$scope.subchapters = data && data.query ? data.query.pages : {};
});
});
});
};
}])
.filter('strip_namespace', ['$sce', function($sce){
return function(text) {
text = text.split(":");
return text.length > 1 ? text[1] : text[0];
};
}]);
.directive('flickity', [function() {
return {
restrict: 'E',
templateUrl: 'templates/view.html',
replace: true,
scope: { chapters: '=' },
link: function(scope, elem, attrs, ctrl) {
scope.$watch('chapters', function() {
elem.flickity({
// settings
});
});
}
};
}]);
angular.element(document).ready(function() {
angular.bootstrap(document, ['FlickityApp']);
var flkty = new Flickity('.gallery');
});
Link to flickity api : http://flickity.metafizzy.co/api.htm

Accessing a service or controller in my link function - Angular.js

I have a directive, but I am having a problem access the controller and my service that is injected into it. Here is my directive:
angular.module('clinicalApp').directive('chatContainer', ['encounterService', function(encounterService) {
return {
scope: {
encounter: '=',
count: '='
},
templateUrl: 'views/chat.container.html',
controller: 'EncounterCtrl',
link: function(scope, elem, attrs, controller) {
scope.addMessage = function(message) {
//RIGHT HERE
scope.resetChat();
};
scope.resetChat = function() {
scope.chatText = '';
scope.updateCount(scope.chatText);
};
}
};
}]);
You can see that I am attaching a couple of functions to my scope inside the link function. Inside those methods, like addMessage, I don't have access to my controller or the service that is injected into the directive. How do I acceess the controller or service?
UPDATE
Here is the service:
angular.module('clinicalApp').factory('encounterService', function ($resource, $rootScope) {
var EncounterService = $resource('http://localhost:port/v2/encounters/:encounterId', {encounterId:'#id', port: ':8280'}, {
search: {
method: 'GET'
}
});
var newEncounters = [];
var filterTerms = {};
EncounterService.pushNewEncounter = function(encounter) {
newEncounters.push(encounter);
$rootScope.$broadcast('newEncountersUpdated');
};
EncounterService.getNewEncounters = function() {
return newEncounters;
}
EncounterService.clearNewEncounters = function() {
newEncounters = [];
}
EncounterService.setFilterTerms = function(filterTermsObj) {
filterTerms = filterTermsObj;
$rootScope.$broadcast('filterTermsUpdated');
EncounterService.getFilterTerms(); //filter terms coming in here, must redo the search with them
}
EncounterService.getFilterTerms = function() {
return filterTerms;
}
return EncounterService;
});
and the chat.container.html
<div class="span4 chat-container">
<h5 class="chat-header">
<span class="patient-name-container">{{encounter.patient.firstName }} {{encounter.patient.lastName}}</span>
</h5>
<div class="chat-body">
<div class="message-post-container">
<form accept-charset="UTF-8" action="#" method="POST">
<div class="text-area-container">
<textarea id="chatBox" ng-model="chatText" ng-keyup="updateCount(chatText)" class="chat-box" rows="2"></textarea>
</div>
<div class="counter-container pull-right">
<span class="muted" id="counter">{{count}}</span>
</div>
<div class="button-container btn-group btn-group-chat">
<input id="comment" class="btn btn-primary btn-small btn-comment disabled" value="Comment" ng-click="addMessage(chatText)"/>
</div>
</form>
<div messages-container messages="encounter.comments">
</div>
</div>
</div>
</div>
Here is Demo Plunker I played with.
I removed scope{....} from directive and added 2 values in controller and directive to see how they change regards to action.
JS
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
// listen on any change of chatText in directive
$scope.$watch(function () {return $scope.chatText;},
function (newValue, oldValue) {
if (newValue == oldValue) {return;}
$scope.chatTextFromController = newValue;
}, true);
});
app.directive('chatContainer', ['encounterService', function(encounterService) {
return {
templateUrl: 'chat.container.html',
link: function(scope, elem, attrs) {
scope.countStart = scope.count;
scope.updateCount = function(chatText) {
alert('updateCount');
scope.count = scope.countStart - chatText.length;
};
scope.addMessage = function(message) {
alert('addMessage');
encounterService.sayhello(message);
scope.resetChat();
};
scope.resetChat = function() {
alert('resetChat');
scope.chatText = 'someone reset me';
scope.name = "Hello " + scope.name;
scope.updateCount(scope.chatText);
};
}
};
}]);
app.service('encounterService', function() {
var EncounterService = {};
EncounterService.sayhello = function(message) {
alert("from Service " + message);
};
return EncounterService;
});
HTML
<body ng-controller="MainCtrl">
<div chat-container></div>
<pre>chatText from directive: {{chatText|json}}</pre>
<pre>chatText from controller: {{chatTextFromController|json}}</pre>
<pre>name: {{name|json}}</pre>
</body>

Angularjs. Accessing attributes from an AngularJS controller

I'm trying to access image src with controller to save it, but can not figure out how to do it.
My template:
<img data-ng-model="book.image"
style="width: 300px; height: 200px;"
ng-src="data:image/png;base64,iVBORw0K...SuQmCC">
<a data-ng-click="save(book)" class="btn">Submit</a>
My controller:
controller('BookEditController', [ '$scope', '$meteor', function ($scope, $meteor) {
$scope.save = function (book) {
if (typeof book == 'object') {
var books = $meteor("books");
var id = books.insert(book);
}
};
}])
One option is using a directive and applying a method called save to it which would handle the src attribute found on the image tag.
JS
var app = angular.module('myApp', []);
app.directive('saveImage', function () {
return {
transclude: true,
link: function (s, e, a, c) {
s.save=function(){
alert(a.src);
};
}
};
});
HTML
<div >
<img save-image style="width: 300px; height: 200px;" src="http://placehold.it/350x150"> <a ng-click="save()" class="btn">Submit</a>
</div>
This is the code implemented in jsfiddle.
Another option is to isolate the scope to a controller but still apply the image to it instead of a function.
JS
var app = angular.module('myApp', []);
app.directive('saveImage', function () {
return {
transclude: true,
link: function (s, e, a, c) {
s.image = a.src;
}
};
});
function cntl($scope) {
$scope.save = function (img) {
alert($scope.image || 'no image');
}
}
HTML
<div ng-controller='cntl'>
<img save-image style="width: 300px; height: 200px;" src="http://placehold.it/350x150"> <a ng-click="save()" class="btn">Submit</a>
</div>
Notice the added ng-controller="cntl".
This is the JSfiddle for that one.
There's probably a better way to do this... pass $event to your controller function
<a data-ng-click="save(book, $event)" class="btn">Submit</a>
and then use traversal methods to find the img tag and its src attr:
$scope.save = function (book, ev) {
console.log(angular.element(ev.srcElement).parent().find('img')[0].src);
...
Update: the better way is to create a directive (like #mitch did), but I would use = binding in an isolate scope to update a src property in the parent scope. (The = makes it clear that the directive may alter the scope. I think this is better than having a directive add a method or a property to the controller's scope "behind the scenes".)
<div ng-controller="MyCtrl">
<img save-image book="book1" src="http://placehold.it/350x150" >
Submit
</div>
function MyCtrl($scope) {
$scope.book1 = {title: "book1" }; // src will be added by directive
$scope.save = function(book) {
alert(book.title + ' ' + book.src);
}
}
app.directive('saveImage', function () {
return {
scope: { book: '=' },
link: function (s, e, a, c) {
s.book.src = a.src;
}
};
});
Plunker

Resources