AngularJS - ng-click in shell page - javascript

I have an Angular JS app in which the header and footer are part of index.html, and the views are loaded dynamically between. I have a signOut() function on the scope in my controllers that makes the proper calls to a REST API to sign out the user. However, the "Sign Out" button is a part of the header, so I'm having trouble getting it to call the signOut() function.
ng-click="signOut()" inside the <button> tag does absolutely nothing, presumably because the button is in the shell page, not one of the views, and so doesn't have access to the scope.
Alternatively to using ng-click, I tried putting some code in my view to call the signOut() function when the button is clicked, since I know I can access it through the DOM. I first tried this:
<script>
$('#logoutbutton').on('click', function(){
{{signOut()}};
console.log("signout clicked");
});
</script>
But that throws Uncaught ReferenceError: signOut is not defined because the scope apparently isn't accessible within the <script></script> tags. For that same reason, I suspect
<script>
$('#logoutbutton').on('click',
{{signOut()}}
);
</script>
would not work, even though trying to use that code throws a syntax error (Unexpected token '{').
I'm trying to find out if there's any way I can call the signOut() function when the logout button is clicked without needing to make the button a part of the view instead of the shell page.
For the curious, I control whether the button is visible by setting display:none by default, and putting this line at the top of all the views where I want it to be displayed:
<script>
document.getElementById('logoutbutton').style.display = 'block';
</script>
which is how I know I can access the button through the DOM, even inside the views.

This worked for me.
<button id="btn">click</button>
$scope.show = function(){alert('msg');}
$('#btn').on('click',$scope.show);

I have to agree with Mostafa Talebi the accepted answer is using a completely different framework and isn't an AngularJS based answer. In fact the only problem I can see with your plunkr is that the main div is missing the ng-controller directive which would need to point at your sign out controller. You would then be able to hook up an ng-click on your button to your sign out function in the regular way. This is essentially what glendaviesnz is suggesting. You wouldn't then need to do the javascript get element and event listening which really isn't the Angular way.
Further to this the use of jquery events in an angular app should be avoided because effectively they happen outside the view of angular or more precisely outside of the angular digest cycle. You can use the $on to list for events in Angular and $broadcast/$emit to broadcast events.
Your requirement is a basic spa with authentication and there are any number of good examples of this Dan Wahlin's CustomerManager springs to mind which demonstrates how to achieve what you want in a purely Angular way.

Related

How can I wait for the create/edit entity modal window to finish rendering and execute my custom js code in 2sxc module?

When user presses either create entity button or edit entity button, there's the same modal window in an iframe that is build by js dynamically. So what I'm trying to do is to wait until it's fully rendered and then execute my custom js code. So is there a proper way to do that? Some sort of event like RenderFinished shooting or something? Don't want to use timeout since I understand that it's not a good way to do that.
What I tried so far is that I've added jquery to the page programmatically, since it's not used currently at that particular page for some reason (probably because iframe is built dynamically without jquery and I needed to add it myself).
After that I tried to access iframe via jquery selector and then on iframe.ready access element inside in the same manner (selector and even ready for that element). But iframe is accessed and element inside it is not. Console log inside ready function just outputs no elements found. When I placed breakpoint inside I saw that there's no modal window built yet and my code is executed synchronously before it. So there's nothing to find yet at that moment.
Oh and I tried to put it all inside $(document).ready, of course. But it didn't change the situation neither...
Any ideas about how to do that properly?
The final goal why am I doing all this complicated dancing: I'm trying to add validation that UrlKey for entity is unique. So I want to bind my js function to UrlKey input's onchange event and call backend api to do the validation and return new UrlKey if it wasn't unique and edit the UrlKey input accordingly. The problem that I stumbled upon is to execute my code after modal iframe window is rendered.
Any tips are highly appreciated.
You are in luck :)
2sxc added a Formula feature which will help you with this. There are videos and tutorials and more. See http://r.2sxc.org/formulas

Angularjs modal windows dynamically (programmatically) built

I need to implement a modal window whose contents is generated by the JavaScript controller (the contents is a hierarchical tree of accordions/panels whose structure is unknown till data is received).
The contents of the modal is defined in a view that includes ng-bind-html directive.
When displaying this just as a normal page (i.e. not as a modal) I get the contents and behavior matching the needs.
My problem is that I can't find the way to make it work as a modal.
Is there any limitation to Angular that I'm unaware of?
The same problem I have with another modal that is also in a view, but its contents is built using ng-repeat directive. In this second case, when I try to deploy data into fields, I get an error stating that the element I'm trying to set its value is undefined. It would appear that such attempt is taking place too early and the DOM is still not ready.
This second case also is not working when attempting to use it in a modal.
The problem may lie with the models that you are using in the modal. You may want to make sure the correct models are even being used. The scope may not be the same in the modal window as it is as a pure template. I like to test which scope things are truly in by using the ng-init or ng-if directives, and creating a function to see if it even gets called. So for example:
HTML template
<div class="panel" ng-if="scopeCheck">
</div>
Controller
$scope.scopeCheck = function() {
debugger; //or console.log('here');
}
If that is not the issue, then I'm not sure if you are creating this modal yourself, but if you are I would suggest maybe using the modal directive from UI Bootstrap and seeing if it works with that.

Angularjs - Reload page even if same url

I'm using Angularjs 1.3, my project has 2 submenus:
href="/submenu"
href="/submenu?page=1"
When I am on submenu page and clicks on second url, the page is not reloading, it simply update the url, but does nothing. I have written the code when user lands on second url with that query parameter.
I don't want to force reload the page with
window.location.reload();, because it will empty the $rootscope.
I have one solution, by redefining url code with Angular ui-router but it is time consuming since redefining will break the major features. I am looking for quick fix right now.
Maybe this works:
...
Check if $rootscope is empty, to make it sure.
I quick fixed it. There was a guy who commented but, removed it now. He said I should call the function with data to update the view, instead of redirecting, and I did that.
But in my case, menu is out of that page's controller scope, I used vanilla js for the link redirection (need to perform some action before redirecting).
So in order to call the controller's function, I checked if I am on the same page, if yes, then grab the angular scope from the page, in order to get all the functions defined in that controller, using:
angular.element($('#someId')).scope();
SomeID should be set on the element on which ng-controller is defined. It gave me all the functions defined in that controller's scope. Then I just called the function and page gets updated, without reloading, problem solved.
Use target="_self":
href="/submenu" target="_self"
href="/submenu?page=1" target="_self"

How to correctly interact with a view which is managed from another controller?

The question might seem too vague but I could not think of a better way to describe the idea, so I'll try to explain it in details.
I have MasterController attached to <html> tag of my SPA application. This MasterController contains all the logic and models for controlling the following UI elements:
page title (<title> tag)
subheader which displays the title of current page (like Customers, Orders, Settings etc.)
name of the currently logged-in user
some commonly used action buttons which will be used for all pages in the system. To be specific, these buttons are Show filters, Export data to Excel and Add new record.
While the first two items on this list can be managed through detection of current ui-router state (through its $stateChangeSuccess event), the last two (username and buttons) are somewhat problematic, especially the buttons.
I can manage the button actions using $broadcast, so every controller can be notified about clicks on any button. But the tricky part here is that the buttons might be needed in different combinations - one page might need all of them, and another one might need none.
Let's say, ui-router loads some CustomersController. At that point MasterController receives $stateChangeSuccess event and by default hides all the buttons.
But now, how does CustomersController tell to MasterController that CustomersController will need two specific buttons from the very beginning?
Theoretically, I could use $emit from CustomersController to send an event to MasterController, but it somehow feels ugly. Events are meant for, well, events and not for sending requests like "hey, MasterController, if you are somewhere up the scope, can you please show the following buttons?".
Of course, I might be wrong and maybe there is some way to use Angular event system to manage this scenario in clean way.
What came to my mind is that maybe in the $stateChangeSuccess event I could somehow detect if there are currently any listeners for my button click events and then I could hide buttons which do not have any listeners attached, but I'm not sure how to do it, and I'm not sure whether it will work as expected - whether old listeners will be detached when ui-router recreates the view with another controller.
If you are just nesting controllers, their corresponding scopes actually make use of prototypical inheritance. So you could just define a function $scope.configureButtons in your MasterController and call this function from the $scope in your nested CustomerController.
If Controllers are not nested you would probably need to resort to $rootScope.$broadcast for setting up your buttons.
Why not just simply using diferent controllers for each view? Maybe generalize a bit the CustomerController and extend it (specialize it) for every combination of buttons you need. Using the $stateChangeSuccess feels like avoiding polymorphism to me.
Today I got a tricky idea based on #Diego Castaño Chillarón 's answer. I thought - but is it possible to use ui-router to swap controller of existing view and will it rebind also the $scope? And will I still be able to replace inner parts of the loaded view?
It turned out that it is doable! Now I don't have to control the common view fragments from the master control, and I don't need also to inherit or duplicate them - I just switch the controller to the required one through ui-router.
Like this:
$stateProvider
.state("customers", {
url: "^/customers",
views: {
"controller": {
controller: "CustomerController as cntrlr"
},
"page#customers": // <- this is important, absolute name required for ui-router to find nested view
{
templateUrl: "customers"
}
}
}) // other routes follow in the same manner
And my HTML looks like this:
<div id="routes-root" ui-view="controller">
<div id="content-header-buttons">
<button type="button" ng-click="master.toggleFilter()">Filter data</button>
<button type="button" ng-click="cntrlr.exportClicked()">Export</button>
<button type="button" ng-click="cntrlr.createNewClicked()">Create</button>
</div>
<div id="view-content" ui-view="page"></div>
</div>
As you see, I left master controller to control only visibility for filters block, which won't change.
But controller itself is attached to #routes-root element, preserving inner content, and ui-router (or Angular) is smart enough to attach $scope and cntrlr variable to the loaded controller. And then I load inner view into #view-content, which also gets attached to the already loaded controller.

Angular JS fires ng-click before loading the resource at href

I have a link/anchor HTML like:
<a href='/some-form' ng-click='someFunction(item)'>Text</a>
What I have in mind is that user clicks this link, then I want to load an HTML from server, and after the loading of that HTML, I want someFunction to be executed, which fills the loaded form with some data.
However, by debugging my code, it seems that Angular JS first fires someFunction function, and then browser loads the HTML. Not only I want this to be reverse, but also I need them to be executed sequentially (synchronously).
Is my design a good design? Is there any other way to achieve this behavior? If not, what should I do to make it work?
so I think someFunction(item) should be in the other controller dealing with the route /some-form.
You may also consider using $location to manually navigate to /some-form.

Categories

Resources