Angularjs modal windows dynamically (programmatically) built - javascript

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.

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

How to reload angularjs scope data without rerendering bound view

I've got a small problem. I have a bootstrap tabset within an angularjs app. The tabs are partially generated from ng-repeat and contain data, that is bound to the scope.
Basically, within the controller:
$scope.data = { ... } // Loaded from a factory
Now, when I reload this data (by replacing the old one with the new one) the tabset will be rebuilt by ng-repeat and the view will automatically switch to the first tab.
Is there a way to replace the data in scope without rebuilding everything in the view?
You aren't explicit about the specific data and which of it is used in what ways.
So this will have to be a general answer:
Try to update only the bits that actually changed.
For example do not replace whole objects or arrays, but only updated properties or indices that actually changed. That way only the relevant parts of the GUI will update.
If you must replace objects, you can still help angular keep the connection between objects in the model and dom elements for ng-repeat if you use "track by" in the expression (which is possible only if the element has some unique id that you can use for that).
Another option: Use one time binding for the parts that should change only exactly once when the data is first loaded: See the section "One-time binding" in https://docs.angularjs.org/guide/expression

AngularJS - ng-click in shell page

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.

KnockoutJs v2.3.0 : "cannot apply bindings multiple times to the same element"

Problem:
In an existing application, I'm adding a new feature which uses knockout to display a grid and some additional information. I load some of the data at the start and prepare subscriptions which load other data using ajax, create viewmodel in Razor view to inject server-side variables, and then bind it (it does not matter if I pass html node or not, I have same problem).
Upon page load, "cannot apply bindings multiple times to the same element" error appears in console, and all of the html elements which use if, with or template bindings are empty.
The only occurrences of "applyBindings" in entire project are in my view, and in knockout source. Debugging shows that it is called twice, both times from $(document).ready
When I remove apply bindings from code, and call it later manually using console, it works.
Answer is already on SO: jQuery $(document).ready () fires twice
Theme of the application was moving/manipulating html elements, and tag with viewmodel initialization was inside same html view which was manipulated later. Moving to separate section which is rendered in head solved problem.

Destroy typeahead after the menu has been closed

I have a searchbox on which I initialize typeahead when I click on it, to some data from the server. Depending on the current page, I need to show/hide a footer in the search dropdown.
I went for the approach to destroy the typeahead and then recreate it, according to my needs. In this way, I also refresh the data from server, in case there's something changed.
For destroy I use this this.$("#searchQuery").typeahead('destroy'); right at the top of the function that needs to initialize the typeahead, but the problem is that the menu is not destroyed. If I look at the dom, there are 4-5 or even more typeahead menu created.
So my question is, how can I properly 'reinitialize' a typeahead menu?
I forgot to mention I am using twitter typeahead
You don't need to reference jQuery via this like you showed here
this.$("#searchQuery")
You should just do
$("#searchQuery").typeahead("destroy");
Without seeing more of an example I would say your problem might be because this inside your function is being bound to a different object than the one you were expecting.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Your line is inside your function so you can not guarantee that this will be Window and you have no need to use it in this case.
If this is not the problem then please provide a full html and javascript example, preferably on JsFiddle.

Categories

Resources