Angular clickOutside directive not working - javascript

I made a div which shows itself depending on a bool (called "menu"), and I wanted to make it so if the user clicks outside of it, the bool changes and therefore, the menu is hidden. I've read a post about this and I've searched a bit about it, and I found that this is already made by some users.
I've tried installing this one, creating the file myself and pasting this code, or even changing the last one to this, but it won't work and I don't know why.
The html is the following:
<!-- Menu tarea-->
<ng-container *ngIf="menu">
<div (clickOutside)="abreMenu(this.tareaMenu)" class="popup-menu">
<p>formulario here</p>
<hr>
<div>
<button (click)="borrarTarea(this.tareaMenu)"></button>
<span>Borrar</span>
</div>
</div>
</ng-container>
You don't have to worry about the "abreMenu()" function, that works just fine.
Both the new directive and the one installed are called the same, but there are no errors. I don't know if I messed the imports up but I'm getting nothing.
NOTE: This html file belongs to a component within "MyModule", which is imported in "AppModule", and there I've imported the "ClickOutsideModule" since I'd probably want to use it globally through the app.
Why isn't it working? Thanks.

Instead using the clickOutside directive you could use a HostListener inside your component:
// somewhere inside your component
#HostListener('document:click', ['$event'])
outsideClick(event: MouseEvent): void {
this.abreMenu(this.tareaMenu)
}

I just experienced this problem last week. My solution was that the directive had to be a part of the "other" module definition, because the component which used it, was contained in that other module.
I didn't try to test if the main app.module components(via the import of the other module) could access the directive, but the problem was solved for all components in that "other" module.
It's just my opinion but I think Angular has some serious issues with it's module system, not to be confused with the JavaScript module system. Angular needs to adopt the JavaScript (only) module system going forward.

Related

Applying a dependency with javascript to Angular 2 such as bootstrap, foundation or jquery

creating this Angular 2 project I am trying to add other dependencies to the global project that incorporate js files and css files.
The css files work fine... but the javascript files seem to not to apply correctly at all.
I am attempting to do this in the root index.html file.
In the dom everything appears to be correct and there are no warning, errors or conflicts which leads me to believe it is an injection issue.
Interestingly if I apply the html to the index.html everything works fine... but adding it to any component makes it useless.
There is something I am probably doing wrong.
You need to bootstrap your external libraries' code when the component bootstraps.
For example, if you are using the bootstrap collapse on some menu items in a component, you need to call $(class).collapse() in the ngOnInit of that component( or anywhere else in the lifecycle of the component ).

Using feature flags in complex UI changes

To simplify matters, lets say there's a single HTML page with it's CSS and JS file. No server.
Now comes a request to toggle features on/off in this simple web UI.
The problem is, for example, a new feature would mean changing the HTML structure to add a new component, so now the HTML is a little different.
Also, the CSS of the page itself needs to change in order to support the new component. also, of course, there is javascript code that needs to be changed to fit with the changes made to the HTML..
Of course, if this component was completely "isolated" and had just it's own CSS, javascript and html template file, it was much much easier, but it does require changes to things around it, to the HTML/CSS/JS of the page it resides in.
How can such a complex process be reduced to a simple "feature toggle"?
Also, to bring the complexity to a new level, this new feature might need changes to some library version used in the project, but that's a whole other level of difficulty when toggling features.. but lets ignore this part on the discussion because I am more interested on the matter mentioned above.
I came up with the following way:
System is basically made out of:
index.html (basic HTML entry point which everything loads into)
HTML template files
SCSS files
Architecture-related javascript files
javascript controllers (kinda like pages. control page events and which components to use in it)
javascript components (imagine tables, grids, tree menus, breadcrumbs...)
home.html template example:
<div class='col'>
<component class='line-chart'></component>
<component class='table'></component>
</div>
<div class='col'>
<component class='bar-chart'></component>
</div>
Steps I did (Simplified):
Create a way to switch features on/off within the UI:
Create aמ architecture (system/app-related) javascript file which its task is to create a dropdown which from a person could choose which features to toggle, and the result is saved in localstorage.
Append the dropdown to the page.
When a user selects a feature, reload the page and after refresh, read the features from localstorage and save them to the architecture state object, under the property "features", to be used later.
Create a feature: "home-v2"
So, I'm working on the Master branch (like a boss) and I want to create some big changes in some page, and add a few components and move other existing ones around. What I did was:
Copy the SCSS file of the page _home.scss and rename to _feature-home-v2--home.scss (it will be automatically imported via the main.scss using globbing)
Copy the template file of the page home.html and rename to feature-home-v2--home.html
Import the javascript components files which will be used to the page controller javascript file.
Write some if statements
This is the "ugly" part, where I must set what to will be done according to each feature. So, for my new example feature home-v2 I will need to do a few things:
go to the home page javascript controller file and go to the line where I load the HTML template, and check if the app State "features" object for
something like this:
var templateName = `home`;
if( app.state.features['v2--home'] )
templateName = `feature-home-v2--` + templateName;
Now that the page is using a different HTML structure, which can look like similar to the default home page but with more components and some are in different order:
feature-home-v2--home.html template example:
<component class='breadcrumbs'></component>
<div class='col'>
<component class='table'></component>
<component class='line-chart'></component>
</div>
<div class='col'>
<component class='pie-chart'></component>
</div>
I can now load the imported controllers to where they reside (before they might have been imported but weren't initialized on the page).
Thoughts on the process:
Hitting ctrl-p in Sublime and starting to type feature- will show only the feature-related files.
Produce larger output from the build process, and doesn't use different GIT branches per-feature.
Features should be merged quickly/discarded so the code won't get messy with many features.
using all the features on a single-branch allows to quickly adding/removing with ease of a custom dropdown with checkbox/radio.
GIT commits must be remembered to be named according to the feature worked on, to maintain GIT order with sensible names.
For more complex changes, other files might be needed to be cloned and renamed, even top-order controllers themselves.
I think the best way to replicate flags is to just create a JSON file with ids that you want hide. Then just have the Javascript FileReader (https://developer.mozilla.org/en-US/docs/Web/API/FileReader) read in, parse the JSON, and hide the mapped ids that are false.
Lets say your toggable feature were the following input boxes:
<input id="input_box"/>
<input id="input_box2"/>
Your text file would contain this:
{
input_box: false,
input_box2: true
}
input_box would be hidden, while input_box2 would be shown. This seems like the only way to enable flags, unless you want to put it in the URL.

'angular-backtop' back to top button not working

Hi I am trying to implement a back to top button as easily as possibly in my angular app.
I found the angular-backtop directive and it seems perfect but I can't get it to work.
I have angular-backtop.js and angular-backtop.css included in my index file and 'angular-backtop' included as a dependency in my main module.
In the angular-backtop.js the use of scope is present (without $) and I know there is a bug where scope doesn't work with the new angular router which I am using. Is this why the angular backtop isn't working?
It seems like this isn't correlated but I'm not sure why else this wouldn't work.
All you have to do is inject that directive anywhere you want into your html file as
<back-top></back-top>

Restart/reload Angular app

I'm working on a project with Yii2 and Angular. The structure of the code is as follows:
<html ng-app="myApp">
<head.../>
<body>
...
<div class="body-content"> MAIN CONTENT GOES HERE </div>
...
</body>
</html>
The page contains a header and a column on the left and a center area which is rendered inside the .body-content div. Now, as you can imagine, I have some buttons in there, some other angular widgets, etc..
Yii2 has a really cool feature called renderPartial that will re-render a view file without wrapping it again in the <head> and <body>. I use that to update the content of my main area, by calling that function, getting the response with jQuery and replacing the content.
Now, that causes all buttons that where binded with Angular to stop working (I'm guessing why). My question is: How can I make Angular re-run or re-bind all my (new) DOM elements to their actions?
You would have to use the manual bootstrap way (explained in https://docs.angularjs.org/guide/bootstrap) for angular but doing that would cause a memory leak over time as angular add listener on DOM that you destroy and is not aware of it's removal, so they stay, and so does for the controller / directives / binding and other features that are referenced by your code.
Is yii2 could be wrapped into an angular directive?
I am not sure if I am getting you right - you use a frontend framework AND a backend framework to control your frontend, the latter one deliveres new DOM content you inject into your HTML?
As far as I got it, Angular is best in handling everything while getting the data (be it from the backend in JSON or other format of your choice), NOT new DOM elements.
Angular itself binds to whatever DOM nodes it is added to, handles the content and dependency injection and thus displays your data. In your case the backend PHP framework seems to hand in new DOM elements that Angular thinks of "Hey - you don't want me to be adding them? fine, then I don't." and breaks.
Maybe there are solutions for this specific case, but if I were you I would rethink the concept in terms of "Where do I want my views/templates to be rendered? What part of the whole is responsible for what?" Using two different frameworks, let alone languages, to do the same job and interfering with one another would make a mess I wouldn't want to clean up.
So if you like this Yii2 feature and want to make it work, fine - but in that case - what do you need angular for? And if you'd rather stick to Angular you just have a backend that handles data and hands it back to the frontend to do it's job with it.

angular modal ui bootstrap: Can i use another controller child of ModalInstanceCtrl?

I'm new in angular and my english is not very good, so i try to explain my problem the best i can.
I'm using the ui.bootstrap.modal in my project, and i need that the modal window i open can be controlled by another controller and not only ModalInstanceCtrl.
I want to ModalInstanceCtrl manage the common actions in a modal window, (set title, close, etc..) and then another controller (SpecificController) manage specific actions.
So this is my modal template view now:
<h1>
{{title}}
<a ng-click="closemodal()">x</a>
</h1>
<div ng-include src="specificTemplate.html" ng-controller="SpecificController"></div>
My idea is that specificTemplate.html and SpecificController can be set as a variables in the future and so having a system for manage modal windows with common actions, and other specific actions for each modal window. The include template works fine, but with the ng-controller label i get the following error:
Error: [$injector:unpr] Unknown provider: $modalInstanceProvider <- $modalInstance
I have SpeficController defined in my controllers section.
In other similar questions in StackOverflow, the problem were that ng-controller="ModalInstanceCtrl" was set in the template, but i want/need another controller for specific actions as a child one.
How can fix this?
There are several ways you can manage this, but first of all - don't inject $modalInstance into SpecificController. If you need to close (or dismiss) a modal from within a scope created by the SpecificController you can do so by using the $close() and $dismiss() method available on the scope.
Having said the above your example is a bit too abstract to provide exact guidance so if you could provide a representative use-case using http://plnkr.co/ you would get more detailed answer.

Categories