Angular.js: How to reload scope? - angularjs

I have some markup and loaded controllers.
Then I load some modal window contents by ajax, which is using one of controllers I have defined before. But looks like this controller isn't being used, because he is not required until modal loaded.
Question: How to make controller work when modal loaded? I tryied $scope.$digest(), got error "digest in progress".
index.html
<html data-ng-app="foo">
<head>
<script src="/js/app.js"></script>
</head>
<body>
<div id="modal"></div>
</body>
</html>
js/app.js
!(function(){
function FormCtrl($scope) {
console.log($scope); // never fired
$scope.Submit = function() {
console.log('submit'); // never fired too :C
}
}
angular.module('foo', []).controller('FormCtrl', FormCtrl);
})();
html content loaded by ajax and inserted to #modal
<div data-ng-controller="FormCtrl">
<form name="signup" data-ng-submit="Submit()">
<!-- form data -->
</form>
</div>
SOLUTION:
$.modal().open({
onOpen: function($e) {
$http.get('/views/' + url).success(function(data) {
$compile(data)($scope, function(clonedElem) {
$e.html(clonedElem);
});
// $e.html(data); was used instead of statement above
});
}
});

If you want to inject new DOM elements into existing Anuglar app. You options are to use
ng-include: This has a src property that takes the url from which partial content has to be loaded. AngularJS would internally compile it. One important thing here is that angular will download the template as soon it encounter ng-include in html.
Download and compile DOM manually using the $compile service which is a more involved process.
If your AJAX content contains a controller defined in ng-controller, AngularJS would create it for you.
But in any case, keep in mind the controller script should have been already wired at the initialization\setup phase.

Related

Controlling html outside the ngview when page changes

I have a single page angular application and this is my index.html file:
<html ng-app="myApp">
...
<div id="bash">...</div>
...
<div id="menu">...</div>
...
<div ng-view></div>
...
</html>
Then I have a home controller with its template and an about us controller with its own template as well. And I want their templates to come up in the ng-view which is happening already but I want the #bash to only come up when the url ends with /home and hide when the url ends with anything else.
I can't do that through the home controller because it's outside the ng-view
and I can't do this through a normal JS file as well because the application loads once.
I can go through each controller and have a js function that changes #bash's css and turns display into false but I'd rather just have a condition in one place and I'm sure it's doable. Any ideas?
Why couldn't you do that from the home controller?
<div id="bash" ng-show="bashShown()">...</div>
...
$scope.bashShown = function() {
return $location.path().endsWith('/home');
};

AngularJS + UI Kit

I'm new to angularJS, When i use UIKit only its working fine (Yii2). When i use with angularJS the Javascript events like(tab, slider, dropdown, etc) not working.. I don't know what i have missed or is the any dependency i have to add it work this. This is my app.js code
var app = angular.module('nApp', [
'ui.router', //
'ngSanitize', // sanitize HTML
'ngAnimate', // CSS and JavaScript ng-animate
'ngRoute', // $routeProvider
'toaster', // toasterProvider
'mgcrea.ngStrap', // bs-navbar, data-match-route directives
]);
And my AppAsset.php file is like this,
public $css = [
'uikit/css/uikit.gradient.min.css',
];
public $js = [
'js/app.js',
'uikit/js/uikit.min.js',
];
public $depends = [
'yii\web\YiiAsset',
'frontend\assets\AngularAsset',
];
In AngularAsset.php I have loaded angular related files(css & js).
Please help me..
the reason you are having problems with integrating uikit components into your angularjs project is because uikit components like accordion or slider in your case, are instantiated the moment they are loaded. What this means is that if you place the slider.js file in the header of the first page you load, and your slider is in another html file not loaded yet, say users.html, then the slider.js file will not attach the component to your element in users.html.
If that doesn't clear things up, let me show you what I mean.
This is your index.html (the first html page you load).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!--loading uikit components in here will not work on other html files -->
</head>
<body data-ng-app="nApp">
<nav></nav>
<div class="container" data-ng-view>
<!--This is where the other html files will load in, like users.html -->
</div>
<footer></footer>
</body>
</html>
And this is users.html with an accordion component.
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.25.0/js/components/accordion.min.js"></script>
<!--This accordion will work-->
<div class="uk-accordion" data-uk-accordion="{collapse:false}">
<h3 class="uk-accordion-title">Title 1</h3>
<div class="uk-accordion-content">content one</div>
<h3 class="uk-accordion-title">Title 2</h3>
<div class="uk-accordion-content">content two</div>
<h3 class="uk-accordion-title">Title 3</h3>
<div class="uk-accordion-content">content three</div>
</div>
To elaborate, the accordion will work in users.html because the javascript file accordion.js is instantiated when users.html is loaded and so the component can attach to the respected element.
I hope this clears things up for you.
An other way is to say at UIkit, to make an 'watcher' on the dom
if you put data-uk-observe on the div.
Ui kit will be in place at this moment
Observe the DOM to auto-init new added components, e.g via AJAX.
If you inject dynamic HTML markup into the DOM via JavaScript, just add the data-uk-observe attribute to one of the parent elements to auto-initialize UIKit JavaScript components.
Usage
<div data-uk-observe>
<!-- inject your dynamic html here -->
</div>
Observe an element via JavaScript
UIkit.domObserve('#element', function(element) { /* apply on dom change within element */ })
Since AngularJS renders the HTML after the digest cycle, you have to re-render the UI component. Let's say for example for have the UIKit accordion:
<div id="myAccordion"
data-uk-accordion="{ showfirst: false }"
class="uk-accordion"
data-uk-observe>
Then, in the callback method from the controller for re-rendering the UI component you have to invoke:
UIkit.domObserve('#myAccordion', function (element) {
UIkit.component.boot('accordion');
UIkit.init(element);
});

Angular binding for dynamically added html div

Sorry, this seems a duplicated questions, but I tried all answered questions close to my question, with no success.
I am trying to introduce angular.js into a legacy system.
the system is using the .load jquery function to dynamically load div content with a page from an ASP.NET MVC page.
my brief html will look like this
<body ng-app="myApp">
<div ng-controller="myCtrl">
any content...
<div id="dyncontent"> </div>
</div>
and my javascript legacy code looks like
$('#dyncontent').load('/showviewcontent');
I added in the dynamic content, some angular directive and binding instruction
my angular code is like this
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function ($scope) {
.....
});
How to make the binding / angular directive works on the newly added content?
You need to manually start the angular module using angular.bootstrap
$('#dyncontent').load('/showviewcontent', function() {
angular.bootstrap(document.getElementById('dyncontent'), ['myApp']);
});

AngularJS not getting activated when loading HTML from script

I have this scenario, I am loading part of HTML (which has AngularJS directives) dynamically via script and I see AngularJS is not getting activated.
here is the example I am looking at. Is there anyway I can tell AngularJS to start bind on document ready? Loading an aspx page containing this widget1 content via a iframe seems to work but I am trying to avoid iframe and use client side script.
Appreciate any help.
<body ng-app>
main content page
<br />
<!-- widget1 -->
<b>Widget1</b>
<div id="widget1">
<!-- load below div via jquery/or any method from a remote html file-->
<script type="text/javascript">
$("div#widget1").load("/widgetsfolder/widget1.htm");
</script>
</div>
widget.htm file has below content.
<div ng-controller="TodoCtrl">
Total todo items: {{getTotalItems()}}
<ul class="unstyled">
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.done" />
<span class="done-{{todo.done}}">{{todo.text}} </span></li>
</ul>
</div>
my controller code below.
`function TodoCtrl($scope) {
$scope.totalItems = 4;
debugger;
$scope.todos = [{
text: 'learn angularjs',
done: false
}, {
text: 'implement angularjs',
done: false
}, {
text: 'something else',
done: false
}, ];
$scope.getTotalItems = function () {
return $scope.todos.length;
}
}`
sample code here
http://jsfiddle.net/devs/RGfp4/
Apero's answer describes what is going on. I believe you are going to want to use ng-include. Your html would look something like this:
<body ng-app>
main content page
<br />
<!-- widget1 -->
<b>Widget1</b>
<div ng-include="'/widgetsfolder/widget1.htm'">
</div>
</body>
AngularJS evaluates the scope and renders the page after it is loaded.
Here, your js script loads the widget html but after Angular already compiled the scope etc.
I believe this will not work this way.
You can use angulars ngINclude to fetch outside documents, but I don't suggest it, it can be buggy. You can get the partials using either $http or $resource, this will fetch the data and compile the angular directives inside.
If you want to load the script using some other method, you can store the data as a string inside the controller and use a $compile directive in order to execute the angular code inside it.

angularjs specific page without ng-incude

I design my pages with angularjs like following
<html>
<head></head>
<body>
<ng-view></ng-view>
<ng-include="'footer-tpl.html'">
</body>
</html>
so whenever navigate to any pages will just change the ng-view, but now I want to have a
page without the <ng-include="'footer-tpl.html'">. How to do that?
I just realized you can use ngHide with ngInclude:
http://plnkr.co/edit/BBpfQBRgtr7tAK6iFRTR?p=preview
HTML
<div ng-include="'footer.html'" ng-hide="hideFooter"></div>
JavaScript
angular.module('test', []).controller('test', function ($scope) {
// TODO set this to true to hide the footer, if you don't set it, it stays visible
//$scope.hideFooter = true;
});
When this patch for ngIf makes it into a release, you can use it in place of ngHide. It seems like it'll prevent footer.html from even being loaded if you hit the right view, but I'm not totally sure on that.

Resources