I am just starting with AngularJS, and I want to integrate it into existing ASP.NET MVC application.
I created simple angular HelloWorld app, that I return in a simple view rendered by a controller action:
<div ng-app="HelloNg">
<h1> Hello {{1+1}} you</h1>
</div>
This worked great - I could see angular expression evaluated properly.
However in our app, the data is often shown in ajax-loaded popups. So bascially the JavaScript makes request to MVC controller, the view gets renderred and is sent back. Then JavaScript stuffs it into a prepared div and shows that div as a popup.
In that case, the angular expression is not processed and {{1 + 1}} is rendered verbatim to the screen. The main page that hosts the popup is standard ASP.NET page - it does not use angular at all, it does however import angular scripts.
From what I understand I should use angular $compile service to let angular know about it - however I am not sure how to set the $scope variable.
Could anybody point me in the right direction? In most of the samples I could see $compile service being used within angular controller or directive, but in my case I am trying to do it from outside of the angular world.
The main page is massive, and I do not want to convert it to angular at this point - so having the popup use angular only would work great for me.
After finding some related questions, especially this one, I was able to figure it out:
// Here data is HTML returned from ajax
angular.injector(['ng']).invoke(['$compile', '$rootScope',
function (compile, rootScope) {
var scope = rootScope.$new();
var result = compile(data)(scope);
scope.$apply();
data = result;
// Here data is same HTML but now it is recognized by angular
... render it to page here ...
}
]);
It probably can be done much better but this seems to work for me all - all angular markup is processed when popup shows - and all bindings seem to work as well.
Related
So I'm working on and application that is a terrible mix of MVC and Angular2.
On my Index page we have a partialview loading the angular app. The index page also has all other javascripts links that are needed to get the angular app working.
This all works fine on the first load, but there's an asynchronous call that calls this grid partial view again and replaces the Angular application with <my-app>Loading...</my-app>.
Question
Is there a way in javascript to reload/restart the angular application after this asynchronous call has been made and the html has been replaced?
Index (main view)
<div>
#Html.Partial("Grid")
</div>
Grid (partial view)
<my-app>Loading...</my-app>
Let me know if I need to do a more in depth explanation.
EDIT
My limited knowledge of Angular suggest that there should be a way to re-run the javascripts that are run on the first load. Isn't it that simple? Just run the boot.js again or something similar? I mean the <my-app> tag is already there.
This was already answered in this GitHub issue a while back but I don't think it is valid on angular 4 anymore
Honestly, This is kind tricky but my idea (I didn't try this) is to do the same on the module bootstrapping level
in the main.ts
export var applicationRef;
platformBrowserDynamic().bootstrapModule(AppModule).then((_appRef) => {applicationRef= _appRef}
);
then you can call destroy() on applicationRef and then you bootstrap the app again to reload it.
Is there a convention when I should create a new controller in my page?
Is it something like 1 controller per page? PageController
Or something like HeaderController, NavigationController and FooterController which is per component?
Any helpful resource will also help. Thanks a lot!
It is better to create one controller for the page content, and one for each component repeated on the page (navbar, footer ...), in order to be reused on other page.
Bests practices here : https://scotch.io/tutorials/angularjs-best-practices-directory-structure (see "modularize" and "components")
I can't find anything to justify my claims so just count on my 2+ years of experience in angular.
These are the cases where I would create a new controller:
1. A new view in the app.
2. A reusable piece of code (can be integrated with a directive).
3. When there's a lot of logic in a view controller I usually create 'sub-controllers' just so it becomes more lean.
Final say about controller - Angular2 & React are saying goodbye to controllers, so I'd recommend to move controller logic either to services or directives.
Cheers
I'm working on an application that is using both Angularjs and Asp.net MVC. One thing that I'm confused about is how exactly I should handle URL's and where should I put my partials?
For example, if I'm trying to create a modal pop up with angularjs like below:
$scope.popup = function (feedback) {
var modalInstance = $modal.open({
templateUrl: '/what/path/goes/here',
controller: 'angularjscontroller',
size: 'lg',
});
}
Do I put my html partials in the regular view folder for my serverside app?
If I need a particular partial can I use the same /Controller/controllerfunction pattern that I would use if I was strictly using a server side mvc application?
How does angular handle something like a layout.html file if I only want a specific partial?
Everything that I've found so far seems like they strictly use one or the other and not both.
Do I put my html partials in the regular view folder for my serverside
app?
I do. I create a separate controller for serving up the views, separate from the controller that serves up the data.
If I need a particular partial can I use the same
/Controller/controllerfunction pattern that I would use if I was
strictly using a server side mvc application?
Sure. As long as that controller only returns a partial view.
How does angular handle something like a layout.html file if I only
want a specific partial?
I may not understand the question here but it doesn't handle that. You need to give it the appropriate template.
I am loading an angular 'template' using ajax. This template renders a bootstrap modal form when I call $compile ... this works, everything fine here. But what I need is support of embedding controllers within this lazy loaded 'template' (Preferably I want to handle this client side so on server side everything can just look normal).
The thing is when I use ng-controller inside this template and define a function controller inside a script tag it fails. It tells me it cant find the controller function. I understand why this is happening, the script has not yet been initialized. I am just looking for a solution. How can I make the embedded script tags initialize first? Should I extract them, inject them somewhere and then compile the remainder? Or is there a more elegant way?
Lets have look in AngularJS documentation and show the integration with the browser event loop.
So you can see that AngularJS have its own event loop, which consists of three phases: compile, digest and apply.
When you call compile it will only loads the html markup and insert it. You should call apply also.
With apply you will set the execution scope. This will register an watcher that listens to changes.
This is my first ever trial with Angular JS and am stuck at a very basic step. I have an AngularJS front end and Grails backend. Below are the code snippets I have followed by my question.
URL Mapping entry:
as
"/graph"(controller: 'Graph')
This is my Grails controller/action which renders the GSP:
as
class GraphController {
def index() {
render(view: "../graph", model: [employeeId: "197040"])
}
}
This is the AngularJS file, which is saved as graph.gsp:
When I give the URL: hostname:port/graph I am able to see the body displayed as "Hi ! Welcome". But, I couldn't figure out a ( simple ) way to read that employeeId and display it as "Hi ! Welcome 197040" ( i.e being able to read that variable employeeId sent from backend)
<div><h3>Hi ! Welcome {{employeeId}}</h3></div> didn't work as expected.
I am sorry if this is too basic a question, but I just couldn't see the answer anywhere.
Try this:
<div ng-init="employeeId=${employeeId}"><h3>Hi ! Welcome {{employeeId}}</h3></div>
This will assign the value of the employeeId within the context of the GSP to a variable available within the context of Angular. To understand what I mean, take a look at the generated HTML source in your browser.
By doing this, the employeeId variable will be assigned within the scope of your Angular controller also.
There is a good tutorial on using Angular with Grails here http://claymccoy.blogspot.com.au/2012/09/grails-with-angularjs-and-coffeescript.html?m=1
Your Angular app runs on the user's browser and has no access to your backend environment. Therefore simply setting employeeId as a backend environment variable does not allow Angular to access it.
I can recommend two solutions to this problem:
1) In the index view (/graph), render employeeId as a JavaScript global in a script tag. In Angular, register the global employeeId as an Angular value. Then you can inject the employeeId value into your Angular controller and render it in the Angular view.
2) Retrieve the employeeId asynchronously via Ajax before your Angular app bootstraps, and register it as an Angular value. Then you can inject it to your controller. I recently wrote a blog post about how this can be done: http://biodegreeprogrammer.blogspot.ca/2014/07/pre-loading-data-asynchronously-in.html
The other thing here is, this is gsp afterall.. and your grails variables will work as per normal like how you defined the layout..
<div><h3>Hi ! Welcome ${employeeId}</h3></div>
Which will be grails pushing that info back....
The alternative is something like this: as shown per service on this demo site..
https://github.com/vahidhedayati/testingarrested/blob/master/grails-app/assets/javascripts/testingarrested/arrestedServices.js
Maybe you wish to try out arrestedplugin for yourself as a demo and then take the for example above service and change it for your own usage..