I'm trying to use AngularJS to update my iframe whenever a query is made. For example, a query is made, then the embed link is retrieved from the database. That link is then used in the iframe. The title and the video are then displayed. This part works for me so far. After that first query though, when I make another query, the iframe does not update, but the title does, so I know that the query is working fine, but there's something wrong with the iframe. How do I update my iframe?
If I do a search that returns one value followed by a search that has multiple results and then another search with a single result, the iframe does change. It changes from the second div to the first div and then back to the second div. So if there's a way to change the div between single searches, the second div can update. Does anyone know how I can do this?
<div ng-if="things.length>1">
<div ng-repeat="thing in things">
<li><a {{ thing.name }} </li>
</div>
</div>
<div ng-if="things.length==1" class="col-sm-4 col-sm-offset-4">
<h1> {{ things[0].name }} </h1>
<iframe width="560" height="315" ng-src="{{ things[0].embed }}" frameborder="0"allowfullscreen></iframe>
</div>
Edit
This is my control.js.
var coreControl = angular.module('myCore', []);
function mainController ($scope, $http, $sce) {
$scope.formData = {};
$scope.things = [];
$http.get('/*')
.success(function(data) {
$scope.things = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
$scope.search = function() {
$http.post('*', $scope.formData)
.success(function(data) {
$scope.formData = {};
$scope.things = data;
$scope.things[0].embed = $sce.trustAsResourceUrl($scope.things[0].embed);
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
}
Another update: Resolved
I've made a Plunker that changes the first object in things on a button click and it seems to update the iFrame like expected.
Check your console and see if there is an error message when you try load the other src. Some sites like google set X-Frame-Options so that the site can't be accessed by your iFrame.
So after randomly finding out that my code works in Firefox, but not Chrome, I did some searching. I found that the Facebook Disconnect plugin was blocking my iframes from rendering. https://productforums.google.com/forum/#!topic/chrome/e3eRJy3vXSM
Related
I have a website with two webpages:
A settings page: webpage with JSON content that looks like this:
{"Sources":["1","2","3","4"]}
A webpage that present all the known "sources" in the system. Just print them one after another.
When my application loading, I downloading the sources page, and save in on my scope at $scope.Settings.Sources.
My AngularJS code:
$scope.getSettings = function (ID, successCallback, failureCallback)
{
$scope.ID = ID;
$http.get("/sources?ID=" + ID).then(function (response)
{
if (response.status == 200)
{
$scope.Settings = response.data;
successCallback();
}
else
{
failureCallback();
}
});
}
function getSettings_success()
{
// Ready to update the ng-repeat NOW.
}
function getSettings_error()
{
alert('Error');
}
$scope.getSettings(1, getSettings_success, getSettings_error);
Now, when i have the $scope.Settings.Sources ready, all I have to do is to print each soruce in specific HTML template. Because of that, I was thinking to use the ng-repeat for this task. Something like this:
<div ng-init="sources=$scope.Settings.Sources">
<ul>
<li ng-repeat="source in sources">
{{ source }}
</li>
</ul>
</div>
Unfortunately, this code isn't working. This because when the page is loading, the $scope.Settings.Sources isn't ready yet. So, the ng-repeat must run after the "sources" page was downloaded.
Is this possible? If yes, how?
You shouldn't be using ng-init for such case, because data is coming by Ajax and you are assigning blank object to source. Cause doesn't responded yet. Rather I'd use Settings.Sources variable directly on your view.
Markup
<div>
<ul>
<li ng-repeat="source in Settings.Sources">
{{ source }}
</li>
</ul>
</div>
Side Note: $scope variable's directly accessible inside angular directives, you don't need explictly specify $scope
We are working with jquery 1.9.1 and angular 1.2.13. We are using a wysiwyg editor that works great, we save the html into the database and load the html back using jquery append function and works fine. Now we are trying to append the same html into a div tag (the wysiwyg editor also uses a div) and the append function it's not working. We check in the console, and the string we are trying to append is there, also jquery grabs the element (also checked in the console log) but the append function it's not working.
PD: I apologize for my english
The html
<div data-ng-controller="PreviewCtrl">
<div class="container">
<div id="resumenPreview"></div>
</div>
</div>
The controller
angular.module('module').controller('PreviewCtrl', ['$scope', '$routeParams', '$location', '$http', 'selectedElement',
function ($scope, $routeParams, $location, $http, selectedElement) {
$scope.id = $routeParams.id;
$scope.mensaje = $scope.id;
$scope.imagen = null;
$scope.dataImagen = null;
//is not working either
$('#resumenPreview').append("hola");
$scope.pageLoad = function () {
var x = selectedElement.data.Resumen;
//This is properly displayed in the console
console.log(x);
//This too, is displayed in the console log
console.log($('#resumenPreview'));
// Why this isn't working? I'am clueless
$('#resumenPreview').append(x);
};
$scope.pageLoad();
}]);
My guess would be there are multiple divs with id="resumenPreview". But this is clearly the wrong way to handle such things in angular. There shouldn't be dom-manipulation in the controller - directives should take care of dom-related stuff. Put the html-string into the scope and let angular handle the injection into the dom:
instead of $('#resumenPreview').append(x); do $scope.resumenPreview = x;
and in the template do this:
<div class="container">
<div ng-bind-html="resumenPreview"></div>
</div>
Solve it with angularjs for the ng-bind-html to work it's necessary to include
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular-sanitize.js"></script>
and to add 'ngSanitize' as a dependency in the app module configuration. And then just do what #Johannes Reuter posted.
Thanks everybody, Greetings.
I am designing a site which has a fixed data set (17 records - each representing a 'book' for sale) and allows navigation between several pages that display details about each of the books. The problem I am having is that when the hyperlink goes to a different view, everything works fine, but if it is hyperlink is to a different book of the same view, it fails to run the controller script. How do I force this to be done.
I have made a minimal executable example:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
<script>
var fooApp = angular.module('fooApp', []);
fooApp.controller('fooCtrl', function ($scope) {
$scope.books = ["Book1", "Book2", "Book3", "Book4", "Book5"]
$scope.selectedBook = "Book1";
var curPath = window.location.toString();
var hashPos = curPath.indexOf("#/");
if (hashPos>0) {
$scope.selectedBook = curPath.substring(hashPos+2);
}
});
</script>
</head>
<body ng-app="fooApp" ng-controller="fooCtrl">
Selected Book: {{selectedBook}}
<ul>
<li ng-repeat="book in books">Visit A {{book}}
</li>
</ul>
<ul>
<li ng-repeat="book in books">Visit B {{book}}
</li>
</ul>
</body></html>
Save the above to two different files: PageA.htm and also as PageB.htm. The selected book is passed as a parameter after the hash mark. You will see the behavior as this: When on PageA you can click on a link to PageB and the book is selected appropriately. But if you click on a link to PageA the URL changes in the address bar, but the controller function does not apparently run. Similarly, on PageB, links to PageA will select a book, but links that stay on PageB do not.
I like the fact that the page is NOT re-read from the server ... it comes out of cache, but I would like to somehow trigger the the controller function again so that the new passed parameter can be read and the correct data displayed. What am I doing wrong?
Update One
Some have suggested to add target="_self" to the hyperlink tag. This works in the simplified minimal example above. Unfortunately, it does not work on fully elaborated site. I don't know why. You can check the full site and the problem is that the "Featured-Book" does not display if you are showing the details of any other book.
Ok. It seems you need to use the $location service and $locationChangeSuccess event in order to keep track url changes. These are part of the Angular core API.
fooApp.controller('fooCtrl', function ($scope, $rootScope, $location) {
$scope.books = ["Book1", "Book2", "Book3", "Book4", "Book5"]
$scope.selectedBook = "Book1";
$rootScope.$on('$locationChangeSuccess', function (event, location) {
$scope.selectedBook = $location.path().substring(1);
});
});
It seems that you are trying to implement a route system.
Have you looked into Angular's ngRoute? check out this example.
ngRoute is great because you can access route data via its $route service or simply via $routeParams.
I am trying to do the following:
<div ng-repeat="audio in event.audios">
<audio ng-src="/data/media/{{audio}}" controls></audio>
</div>
But when I load the view, the {{audio}} variable is not parsed but hardcoded into the source as is. However, if for example, I place that same variable outside of the audio tag it renders the name of the audio file correctly. I've tried using both src and ng-src to no avail.
Is there a way to get the variable to work within an audio tag?
Thanks in advance.
I'm not all that familiar with the ngSrc directive outside of using it on images, but it might require an img tag somewhere in the source.
Try this:
<div ng-repeat="audio in event.audios">
<audio ng-attr-src="/data/media/{{audio}}" controls></audio>
</div>
The ng-attr- directive can be used for any attribute that doesn't have a specific role in angular. You can read more about it on this page.
Update, I was wrong.
I created a jsfiddle and found the actual error that was occurring.
You're getting an error from the sce service. See the SO question here.
The solution is to use $sce.trustAsResourceUrl().
Example:
angular.module('AudioTest', [])
.controller('AudioTestCtrl', function($scope, $sce) {
$scope.event = { 'audios': [
$sce.trustAsResourceUrl('/data/media/test1'),
$sce.trustAsResourceUrl('/data/media/test2')
]};
});
Here's the fiddle.
Update #2
If you don't want to set the url as hard coded or loop through after you get a response from the server, you can use a custom filter to accomplish what you're looking for. This method does not use interpolation, which is where the error is being thrown.
JS:
angular.module('AudioTest', [])
.filter('trustedAudioUrl', function($sce) {
return function(path, audioFile) {
return $sce.trustAsResourceUrl(path + audioFile);
};
})
.controller('AudioTestCtrl', function($scope) {
$scope.event = { 'audios': ['test1', 'test2']};
});
HTML:
<div ng-app="AudioTest">
<div ng-controller="AudioTestCtrl">
<div ng-repeat="audio in event.audios">
<audio ng-src="/data/media/ | trustedAudioUrl:audio)" controls></audio>
</div>
</div>
</div>
And the new fiddle.
Ok, thanks to theJoeBiz's input and some thinking around I solved this by making a directive, here is the code:
app.directive('audios', function($sce) {
return {
restrict: 'A',
scope: { code:'=' },
replace: true,
template: '<audio ng-src="{{url}}" controls></audio>',
link: function (scope) {
scope.$watch('code', function (newVal, oldVal) {
if (newVal !== undefined) {
scope.url = $sce.trustAsResourceUrl("/data/media/" + newVal);
}
});
}
};
});
Then on the template I used it like so:
<div ng-repeat="audio in event.audios">
<div audios code="audio"></div>
</div>
It is all working fine now.
Hey FWIW i found this page looking for a solution to template URL's for my audio tag. However I am using multiple source tags for cross browser support:
<audio id="myAudioTag">
<source ng-src="{{sceSoundUrlMp3}}">
<source ng-src="{{sceSoundUrlOgg}}">
</audio>
First I solved SCE issues by whitelisting *.ogg, *.mp3: (keep 'self' otherwise your future requests fail)
.config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
"self",
/(mp3|ogg)$/,
]);
})
This stopped giving SCE errors but Firefox reported 'no source' and didn't notice the src tag angular added.
The last step was to call load on the element after trusting and setting $scope.sceSoundUrlMp3: $('#myAudioTag')[0].load()
I have used $sce.trustAsResourceUrl("/data/media/" + newVal) but it didn't work for.What seemed to work for me was to put document.getElementById('player').src = {{url}}
in the controller
Hope that helps someone else
I have an angularjs-Application.
In one Controller i´m waiting for an image source address - I get this from an PHP-Service.
controller.controller("LayoutCtrl",
["$scope", "$http", "$route",
function($scope, $http, $route) {
$scope.$route = $route;
$http.get('zkLib/services/header.php').success(function(data) {
$scope.header = data; });
}]);
The header.php looks like this:
$result = array();
$result['index'] = db()->loadSetting('index_page');
$result['banner'] = db()->loadSetting('site_banner');
echo json_encode($result);
So in my template i´ve written:
<div ng-controller="LayoutCtrl">
<div desc="header">
<a desc='hp_link' href="#{{header.index}}">
<img desc='banner' ng-src="zkLib/f/img/{{header.banner}}">
</a>
</div>
</div>
My Problem is now:
When the site opens, it shows the "NoImage"-Icon from the Browser while waiting for this service.
After this the image will be viewed correctly.
But in my COnsole i have this error too:
Resource interpreted as Image but transferred with MIME type text/html: "http://localhost:160/cms/app/zkLib/f/img/".
On my Server i have the image 'loading.gif', i want to show this while i´m waiting for my service.
How to solve this? Could someone help?
The reason you are getting the error in the console is because, before the request to header.php completes and angular renders {{header.banner}}, its trying to load just "zkLib/f/img/". You can fix this by putting the entire relative url into the {{header.banner}} scope property.For example...
<img desc='banner' ng-src="{{header.banner}}">
and make header.banner be the full relative path...
$http.get('zkLib/services/header.php').success(function(data) {
$scope.header = data;
$scope.bannerImage = 'zkLib/f/img/' + $scope.header.banner;
});
Now, before the request is complete, the image src will be an empty string and it won't show the broken image icon or throw the error. If you want to show a loading image before the controller loads, you can just set src, like this...
<img desc='banner' ng-src="{{bannerImage}}" src="/path/to/loading.gif">
Before the request is complete, the src will be the loading.gif file. Once the request completes, ng-src will kick in and your header.banner image will be displayed
When the controller is instantiated, $scope.header is still empty.
This makes ng-src="zkLib/f/img/{{header.banner}}" to be evaluated to this relative path:
'zkLib/f/img/' // translates to "http://localhost:160/cms/app/zkLib/f/img/"
What you need to do is to keep ng-src empty while $scope.header is empty.
#1) One way is to write this:
<img desc='banner' ng-if="header" ng-src="zkLib/f/img/{{header.banner}}">
#2) Or this (if you don't want to use ngIf):
<img desc='banner' ng-src="{{ header && 'zkLib/f/img/' + header.banner }}">
#3) But I would prefer to create the link inside the controller:
$http.get('zkLib/services/header.php').success(function(data) {
$scope.header = data;
$scope.banner = 'zkLib/f/img/' + data.banner;
});
And then just use it easily:
<img desc='banner' ng-src="{{ banner }}">