Im new at AngularJS, and i have this problem;
I fill part of my view with html from a variable in my controller:
<div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div>
Everything goes fine until i decide to run a script. The script is shown, but it doesn't run. I think the problem is the view is filled with my variable controllers after loading the page, so the script doesn't run.
The reason that i am using a variable in my controller to storage the script is because i will have to get the script from somewhere else, and its frequently changed.
Is this a viable way to run my script?.
Here is an example of my code:
View:
<div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div>
Controller:
.controller('browseCtrl', function($scope,$sce) {
$scope.video = '<div id="idxx1" style="width: 460px; height: 290px;" itemprop="video" itemscope itemtype="http://schema.org/VideoObject"></div><script>addeere3ejs("idxx1", "172653", "24431581", "1_fq2w6oc2");</script>';
$scope.deliberatelyTrustDangerousSnippet = function() {
return $sce.trustAsHtml($scope.video);
};
})
If my question it is unclear i would try to explain it better.
You can use the viewContentLoaded event in your controller.
$scope.$on('$viewContentLoaded', function(){
// Run after view loaded.
});
Not exactly sure if ng-bind-html will allow a script to be ran like that. You may need to wrap it in angulars brackets to auto-run on load.
<div ng-bind-html="{{deliberatelyTrustDangerousSnippet()}}"></div>
My work around was to run a $scope function like this with a known variable(s) that will change:
{{postBind(results)}}
Then have a method in your controller to do this
$scope.postBind = function (obj) {
running_my_extenal_methods();
}
Related
I have an SPA written in AngularJS. The main page uses an ng-include attribute to determine which view to load. This is set in JavaScript when someone clicks on a menu which is contained within the main page. However, I've come across a situation where I need to load a different view by clicking a button within another view, essentially replacing it.
I'm trying to figure out how to do this and from what I've researched, I have to use $rootScope and either an $emit or $broadcast call in the child view and a $rootScope.$on method to detect this event.
The thing is, this doesn't seem to work. I have set my breakpoints and stepped through the code, but I always get this error:
Error: [ngModel:datefmt] http://errors.angularjs.org/1.5.7/ngModel/datefmt?p0=2009-07-21T00%3A00%3A00
Here's the code in my parent page controller:
$rootScope.$on('viewChanged', function () {
var menuItem = {
template: 'customerOrders.html' // will be eventually dynamic
};
navigate(menuItem);
});
function navigate(menuItem) {
$scope.activeMenuItem = menuItem;
}
<div data-ng-include="activeMenuItem.template"></div>
In the child page controller:
function changeSelectedView(viewTemplate) {
$rootScope.$emit('selectedViewChanged', viewTemplate);
}
Obviously I'm doing something wrong here. How do I accomplish what I want, or is there a completely different way to do this?
you can use ng-route to work between views. check https://docs.angularjs.org/api/ngRoute/provider/$routeProvider
First of all, the event name in the $emit function and in the $on function did not match, so I made that fix.
function navigateToNewTemplate(event, viewTemplate) {
var menuItem = {
template: buildTemplateUrl(viewTemplate)
};
navigate(menuItem);
}
$rootScope.$on('selectedViewChanged', navigateToNewTemplate);
function changeSelectedView(viewTemplate) {
$rootScope.$emit('selectedViewChanged', viewTemplate);
}
I'm looking to have a function run every time an angular directive updates. In my case, I have an array of modal configurations that get used on a modal markup template.
Every time the template is used to generate a modal due to a change in the model, I want to run a positionModal() method.
scope.$watch in the link function doesn't seem to notice when I change the model, and I cant think of any other way of doing this. I tried a post-link function thinking that the compile function would get called when the directive was applied, but that doesn't seem to work either. Here is my example controller:
MyApp.controller("ModalController", function () {
//Define scope vars
$scope.modals = [];
$scope.$on("modalTrigger", function (event, settings) {
$scope.modals.push(settings);
});
});
Note: I've simplified the controller here- know that it DOES work.
Here is the template code:
<div class="modalParent" ng-controller="ModalController">
<div id="{{modal.id}}" class="modal" ng-class="modal.type" ng-repeat="modal in modals">
<div class="content">
<h2 ng-show="modal.title">{{modal.title}}</h2>
<p>{{modal.message}}</p>
<button>{{modal.button}}</button>
</div>
</div>
</div>
The directive is currently like this:
MyApp.directive("modalParent", function () {
var positionModals = function (element) {
element.find(".modal .content").each(function () {
//position logic here
});
};
return {
restrict: "C",
compile: function (tElement) {
positionModals(tElement);
}
};
});
Note: Also simplified for the purposes here.
The positionModals() call works when the first modal gets pushed to the array. After that, it stops working.
I've tried using the linking function as well, same result. scope.$watch(modals, function(){...}) does not work.
Can somebody help me figure out what I'm doing wrong?
Figured it out!
I was applying the directive to the parent, ".modalParent".
The ng-repeated element in this case is the modal itself ".modal".
You would want the directive to run on elements that get updates as the model changes, because then the linking function will get called each time the element is instantiated, rather than sitting and watching the parent and trying to update from there.
Hope this helps somebody.
Instead of calling like this, my approach is to write this in the services and inject that services in the controller wherever you want to get that function or the data to be notified as,
Services.js
as.service("xyzservice",function(factoryname){
//here the code goes...
})
Now inject in Controller,
ac.controller("controllername",function(xyzservice){
})
ac.controller("controllername",function(servicename){
})
ac.controller("controllername",function(xyzservice){
})
Here we have injected it in the two controller, we can get it.
I have a simple website that implements jQuery in order to create a Slider with some images in the Index.html top banner.
Now, I want to use AngularJS so I'm breaking the HTML code into separate partials.
Header
Footer
Top Banner
If I run the Index.html in the original version (without applying AngularJS patterns) then I can see the slider working perfect.
When applying AngularJS patterns, I moved the top banner HTML to a partial html and then applied ng-view to the div where the top banner is originally located.
var app = angular.module('website', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider.
when('/about',{templateUrl:'app/partials/about.html'}).
when('/contact',{templateUrl:'app/partials/contact.html'}).
otherwise({redirectTo:'/home',templateUrl:'app/partials/home.html'})
});
When I refresh the page the slider is not working, is rendered as simple html without any jQuery effect, is really a mess.
This partials has some jQuery plugins that usually activates by document.ready. But this event not fire when angular load partial in ng-view. How can i call this event to initialize jQuery plugins?
Any clue how to fix this?
Appreciate any help.
When you specify your routes, you can also specify a controller, so your routes would look like this:
var app = angular.module('website', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider.
when('/about',{templateUrl:'app/partials/about.html', controller: 'aboutCtrl'}).
when('/contact',{templateUrl:'app/partials/contact.html', controller: 'contactCtrl'}).
otherwise({redirectTo:'/home',templateUrl:'app/partials/home.html', controller: 'homeCtrl'})
});
Now, you can define inside each controller what you want to do, jquery-wise, as part of a function, like this:
angular.module('website').controller('aboutCtrl', ['$scope', function ($scope) {
$scope.load = function() {
// do your $() stuff here
};
//don't forget to call the load function
$scope.load();
}]);
Make sense?
The other provided answers will work, but they are bound to controllers, and therefore not as scalable and reusable.
To do it the real "Angular" way as mentioned in the comments, you should be using a directive. The benefit to this is that you're able to create several instances with the same code, and can pass in attributes to the directive logic to "customize" the directive. Here's a sample of a way I've used it using bxSlider plugin:
JS:
app.directive('slider', ['$rootScope', function($rootScope) {
return {
restrict: 'EA',
templateUrl: '/path/to/template',
link: function(scope, iElement, attrs) {
//attrs references any attributes on the directive element in html
//iElement is the actual DOM element of the directive,
//so you can bind to it with jQuery
$(iElement).bxSlider({
mode: 'fade',
captions: true
});
//OR you could use that to find the element inside that needs the plugin
$(iElement).find('.bx-wrapper').bxSlider({
mode: 'fade',
captions: true
});
}
};
}]);
HTML:
<div slider some-attibute="some-attribute"></div>
And inside your directive template you could have the slider wrapper and slides, which you could build dynamically using ng-repeat bound to scope data.
I'd recommend reading this excellent article by Dan Wahlin about creating custom directives and how to fully harness they're power.
I had the same problem, I was loading some nav links in a ng-include and I have a script file called on my index.html with jquery instructions to make links active and It i not see the included content.
I tried all of the above solutions and for some reasons, none of them worked for me. When the content is not included (straight in the index.html) jquery kicks in fine but once included it stopped recognizing my elements.
So I simply wrapped my instructions in a setTimeout() function and it worked! Maybe it'll work for you too?
setTimeout(function() {
$("nav ul li").click(function() {
$("nav ul li").removeClass('active');
$(this).addClass('active');
});
});
Somehow the setTimeout() manages to load the script AFTER angular is done loading included content.
Happy coding everyone !
A Directive is certainly a good option, but you can also add a controller to any partial, which will perform all tasks (also with jQuery if you want) after the partial is loaded:
Example: partials/menu.html
<div ng-controller="partialMenuCtrl">
...
</div>
I had the same issue, I was running Jquery slick slider in simple html page it was working fine. How it works basically by including the slick.min.js file underneath the jquery.min.js file and then in script tags you need to initialize the plugin with options like e.g.
$('.items').slick({
infinite: true,
slidesToShow: 3,
slidesToScroll: 3
});
now coming back to the issue, when I added Angular JS to my page and made partials of the page and then went back to the browser to check weather the page was working fine or not, the page was working fine except the slider. Then I tried to move those slick.min.js and plugin initialization to the partials, and it worked :)
How it worked I don't know the reason, since I am new to Angular but it worked and I am still wondering the reason.
I know it is an old thread but just for the sake of completion, you can use the following JQuery code. It is called event Delegation.
$("#anyDivOrDocument").on('click', '#targetDiv', function(event) {
event.preventDefault();
alert( 'working' );
});
I bought a html5 template and tried to integrate with my angularJS web app. I encountered the same issue. I solved it using:
Put the code below at where you put your <script src="vendor/61345/js/script.js"></script> code.
<script>
document.write('<script src="vendor/61345/js/script.js"><\/script>');
</script>
I want to create a really simple confirmation box using UI-modal, which I have successfully used to make complicated modals that load their template and controller from external files in the past.
It's so simple though that I don't want to rely on external template and controller files, just a simple box with a close button which is somehow wired up to a controller declared directly on the modal instance.
Here is what I have tried unsuccessfully...
var modalInstance = $modal.open({
template: "<div>Message goes here...<button ng-click='cancel()'>Continue</button></div>",
controller: function(){
$scope.cancel = function(){
alert("Cancelled");
};
}
});
Looks like you need to inject $scope into your controller function
controller: function($scope){
The scope of the modal template is not the same as the scope in the controller that you've defined the modal instance in.
The reason you're not getting undefined errors is $scope is a closure variable so adding .cancel() to it works just fine. But, since it isn't the same scope of the modal, so the ng-click doesn't see a .cancel() on its scope.
I replicated in this jsbin: http://jsbin.com/gejuxije/1/edit
Edit:
Since you mentioned you didn't want external files for a template, here's a demo of how to define the template for the modal inside the template of the view it is used on.
http://jsbin.com/gejuxije/2/edit
You can put html inside of an inline script...
<script type="text/ng-template" id="myModalTemplateName.html"></script>
The value you pass to 'template' needs to be valid HTML, and ideally should contain the appropriate modal CSS classes.
You may also need to pass in the scope for the controller.
var modalInstance = $modal.open({
scope:$scope,
template: "<div>Message goes here...<button ng-click='cancel()'>Continue</button></div>",
controller: function(){
$scope.cancel = function(){
alert("Cancelled");
};
}
});
In general I have not had to do this, but since you are defining the controller in the open method it may be necessary. According to the docs it should create a new scope as a child of rootScope, but I suspect your mileage is varying. I wish the instructions on the website were a little more informative on this topic.
You may also want to try $close and $dismiss. I've never tried them, but since you are not having luck with the scope variable these might be what you need.
I am just trying to do something similar and stumbled across this. I know it's old but it might help someone.
Simply put
modalInstance.close();
in the cancel function
I'm trying to use a jQuery plugin (Plupload) with AngularJS. I have created a directive that will be my file upload "widget". The directive looks like this (The code in the link function is a very simplified version of the example on the Plupload site):
.directive('myFileUpload', function () {
return {
restrict: 'E',
replace: true,
link: function(scope, element, attrs) {
scope.uploaderProperties = {
runtimes : 'html5,flash,html4',
url : 'media/upload',
max_file_size : '10mb',
container: 'fileUploadContainer',
drop_element: 'fileUploadDropArea'
};
scope.uploader = new plupload.Uploader(scope.uploaderProperties);
scope.uploader.init();
scope.uploader.bind('FilesAdded', function(up, files) {
scope.$apply();
});
},
templateUrl: 'upload.html'
};
});
My upload.html file looks like this:
<div id="{{uploaderProperties.container}}">
<div id="{{uploaderProperties.drop_element}}" style="border: 1px black dashed;">Drop files here<br><br><br></div>
Files to upload:<br>
<div ng-repeat="currFile in uploader.files">{{currFile.name}} ({{currFile.size}}) </div>
<br><br>
<!-- for debugging -->
{{uploader.files}}
<br><br>
</div>
When I include the directive on my page with a <my-file-upload> element, all the data bindings happen correctly. The problem is, when scope.uploader.init(); runs, the ids haven't been inserted into the DOM yet, and so Plupload complains and breaks since it can't select those elements. If I just hard-code the fileUploadContainer and fileUploadDropArea ids in the template, it works just fine. However, I'd really like to define those ids in only one place.
So, is there any way I can run the init() on the uploader after the template is linked in? I thought about using $timeout to delay when it runs, but that seems like a pretty big hack to me. Is there a more correct way of accomplishing this?
UPDATE
I wrapped the init() in a $timeout like this
$timeout(function() {
scope.uploader.init();
}, 2000);
just to make sure it would behave the way I was thinking, and sure enough, with this delay the plugin gets set up correctly and works. However, I do not want to have to rely on the timing of the $timeout. If there was just some way I could call scope.uploader.init(); after the template is linked in, everything should work fine. Anyone know of a good way of doing this?
Your problem is actually the other way around - The link function happens after the template is put in. So in this case, scope.uploaderProperties isn't set when the template happens.
It looks like your template is too fancy for the templateUrl option, really. You could try manually setting your ids with jQuery, or setting everything up in the compile function.
http://docs.angularjs.org/guide/directive