Angularjs animate ngClick + ngShow with custom directive (mySlide) - javascript

I'm trying to get the same ultimate functionality as ng-click + ng-show, except that I want the show to slide in instead of suddenly appear by toggling display: block/none;. I've got the jQuery animate I need, and I've set up the ng-click. I've got 2 problems, but the second might be a result of the first:
Problem 1
ng-click does not change the value of aside_users. I saw SO#12202067 which seems to be a similar situation, but I don't understand how/why their custom directive works and the native ng-click doesn't.
I see the scope: { … } after restrict: 'A',, but that appears to make $scope values available within the newly-created DOM element (my elements already exist and show up just fine, but no triggers/events are happening).
infobox.html
<aside
class="users"
ng-include src="'views/users.html'"
my-slide={"direction":"left","condition":"aside_users"}
></aside>
<i
class="icon icon-user"
ng-click="aside_users=!aside_users"
ng-init="aside_users=false"
></i>
The above code is a $compile'd template and elsewhere within the template I print out the value of the $scope parameter aside_users (prints false).
Problem 2
my-slide doesn't seem to be initiated/triggered (the logging of 'elm: ', elm doesn't appear in Chrome's console). I verified that directives.js is linked in my index.html page.
EDIT I remembered to link directives.js in index.html, but I forgot to add it to the resources array in app.js.
Plunkr
P.S. I'm not sure if <aside attr={object}> is strictly valid, but legitimate browsers seem to accept it in test cases (didn't bother to check IE). My alternate plan is to use 2 attributes: <foo my-slide="direction" my-condition="boolean"></foo>

Related

change an angularjs nested template at run time

I have a template which is nested inside another template which I want to load when i click on a button.
So the nested template is loaded dynamically. This is what I have done so far.
This is the main body.html (this loads when a url is provided in the browser e.g. http://url#/newtemplate)
<div ui-view> </div>
Other section of the code has been removed for brevity
This is the new_template.html which I expects it to show when I click a button.
When I put a template name directly like below i.e. when I hard code it
<div ui-view="number1"></div>
It loads the template fully.
This is the dynamic model
<button ng-model="template_name" ng-value="number1">Button1</button>
<div ui-view="{{template_name}}"></div>
{{template_name}}
The above does not load the template as I expected. but it shows the string number1 when
the button is clicked
What can I do for it to load the template....
This is my controller
.state('parent',{
url: '/newtemplate',
views:{
'':{
templateUrl: "parent.tpl",
contoller:"controller",
},
'number1#parent':{
templateUrl:"number1.tpl",
contoller:"formcontroller"
},
'number2#parent':{
templateUrl:"number2.tpl",
contoller:"formcontroller"
},
'number3#parent':{
templateUrl:"number3.tpl",
contoller:"formcontroller"
}
}
})
Strange enough when I used the dot notation it did not work so I have to use the absolute naming method.
I also noticed that when I added the nested views as shown above the time it takes before the template gets loaded take a very long time.
Please I would appreciate any help which can allow me to load a nested view at runtime (possibly very fast)
Expecting more answer
I still hope that the I can make use of ui-view/ui-router because of the ability to make use of controller.
I'm not sure you can use uiView to load html dynamically.
I would try another possible solutions:
Use directives
Using ngInclude
I'll leave you an example with ngInclude: https://next.plnkr.co/edit/M5hl71mXdAGth2TE?open=lib%2Fscript.js&deferRun=1&preview

AngularJS custom directive loosing root properties

I have created a sidebar custom directive. It's working properly as it loads on where it should. What isn't working properly are the tags. Their supposed behavior is that of a drowpdown, where when clicked they show their inner elements. It works properly when the code is pasted directly but not when the directive is called with the code inside the other html file. I took 2 screenshots to show the difference between using a class="page-sidebar" inside the file that contains the html code of the directive and using it on the "root" file:
It's pretty clear that several properties on the highlighted lines are not being applied on the first one.
Please help as I need this as a "partial" view to be used across several pages.
EDIT: Directive code:
app.directive('sidebar', function () {
return {
restrict: 'E',
templateUrl: "/app/views/sidebar.html"
};
});
EDIT2:
Adding this in the post because it might be confusing from how I explained it:
I see where the confusion might be but they're different things. < sidebar > is a directive created by me. class="page-sidebar" is from the template I'm using and is what formats everything to its place. I tried to insert the class="page-sidebar" into the directive to see if it would work, but they're different things.
EDIT3:
To clear up the confusion, I hope: both pics show the sidebar is working. I know it's an element and as such I'm using < sidebar >, it's working, this is not the problem. The problem is when I use it, the contents such as Dropdowns (as shown in the second pic) don't work when I click them, while when the element contents are simply pasted into the index.html and not in the sidebar.html, it works.
EDIT4:
Found the issue but still no solution. I changed some stuff up and instead of the sidebar it's now on the widgets. Sidebar is now always loaded and it's the page contents which are loaded depending on the URL. This helped me track down the issue:
$(".owl-carousel").owlCarousel({mouseDrag: false, touchDrag: true, slideSpeed: 300, paginationSpeed: 400, singleItem: true, navigation: false,autoPlay: true});
The previous code is in a plugins.js file which is included in the html. For some reason, this line is NOT being run when the page is loaded. When I ran this line in the chrome console, the proper widget appeared.
For some reason, the js contents are not being run when the page loads.
Your main problem is the restrict: 'E',, which is restricting it to elements. This explains why it works for <sidebar>, but not for <div class="sidebar">. If you want to use classes, you need to change it to restrict: 'C'.
Another problem is that when you are trying to use the directive as a class, you are using class="page-sidebar" rather than class="sidebar".
See the docs for directives.
From angular documentation:
The restrict option is typically set to:
'A' - only matches attribute name
'E' - only matches element name
'C' - only matches class name
'M' - only matches comment
These restrictions can all be combined as needed:
'AEC' - matches either attribute or element or class name
The directive definition object for your sidebar quite clearly states that it will treat a DOM node with the tag name sidebar to render the directive template due to the restrict : 'E' property.
So use the directive as an HTML node, and NOT in a class (as it would require the property restrict to be set to C letter).
<sidebar></sidebar>

How to dynamically remove a `md-tooltip` with Angular Material?

I have a basic md-button with a md-tooltip inside. Although, I require a way to globally remove all tooltips from my website if the user is on a mobile device.
<md-button class="md-primary md-raised">
Hello
<md-tooltip>This is a buttons tooltip</md-tooltip>
</md-button>
After the template is loaded and directives have run, the above gets converted into the following:
<button class="md-primary md-raised md-button md-ink-ripple" type="button" ng-transclude="" aria-label="Hello">
<span class="ng-scope">
Hello
</span>
<div class="md-ripple-container"></div>
</button>
There button element no longer contains the md-tooltip, otherwise I'd simply just remove the tooltip element.
The reason for wanting to do this is because on mobile, the md-tooltip eats the button click. Therefore having the tooltip displayed on the first click and the buttons click action on the second click. This is definitely not a desirable effect.
How can I remove all tooltips from all elements on my page so that my buttons click action is the first click/tap instead of the second?
Ok, so I've successfully implemented my suggestions earlier, here's the DEMO
I created another version of md-tooltip just to override angular material's version of it. Then I created an angular.decorator to choose which directive version of md-tooltip will angular use.
app.directive('mdTooltip', function(){ //create your overriding directive
return{
replace: true,
template: '<span style="display:none"></span>',
scope: {}, //create an isolated scope
link: function(scope, element){
element.remove();
scope.$destroy();
}
};
});
app.decorator('mdTooltipDirective',function($delegate){
var version = 0;
var onMobile = false;//do your checking here
if(onMobile) //here comes the switching
version = 1;
return [$delegate[version]];
});
the Directive word in mdTooltipDirective is important, to say to angular that we want to select it for the Directive not a service.
EDIT: I added a link function and removed the element that is placed by the overriding directive
I don't see any mention on their docs on how to do this.
There are two ways that I can think of to work around this.
display: none all <md-tooltip> if your on a mobile device.
override the mdTooltip directive then conditionally $compile the original md-tooltip or a blank one (if you are on a mobile)
HTML
<md-tooltip md-direction="bottom" class="tooltip">Tooltip Bottom</md-tooltip>
CSS
#media(max-width:599px) {
md-tooltip.tooltip {
display: none !important;
}
}
As per this issue, the md-tooltip is the buggy code.
In that case, I suggest you show the tooltip code based on the condition, i.e. only display the content if you are in a web browser.
For this task, you can use the ng-device-detector lib:

Using the same directive in a directive [angularjs]

I have a need to use the same directive within a directive, depending on a conditional param. However, when ever i try to do it, it seems to go to an endless loop. As i understand, it tries to pre-load the templates and that causes an endless recursion and at the end, it just throws me the following error:"RangeError: Maximum call stack size exceeded".
I have created an example in fiddle.. as you can see in the example, when the param's value is "1", it creates the error (even when the second level param is valued as "2" so it shouldn't have real recursion issues in the controller/app).
https://jsfiddle.net/qh9nh1gx/
"custom-directive"'s template:
<div>
<div ng-if='info==1'><div custom-directive info='2'></div></div>
<div ng-if='info==2'>DONE,single.</div>
</div>
Thanks
I have found 2 options to deal with the issue, the first one, is exactly what Jju described - creating a new "compiler" method (it can be grabbed from the url he sent).
The second option - always using an additional template for the "recursive" parts of the directive. For example, in my directive, i had a "ng-repeat" part that depending on the items value, it could request to display the directive again. while i used "ng-include" to have the other directive, it worked.
<div ng-repeat="item in items" ng-include="'inline-possibly-recursive-template"'></div>
in that template, you can call the directive again without any issues..
I hope that it will anyone else that will stumble into that issue.
You can look into https://stackoverflow.com/a/19065910/1680674 that describe a common approach to create directive that use himself inside

AngularJS error when wrapping jQuery plugin in a directive

I'm working on a directive for AngularJS that builds a taggable element and utilizes TagsInput
Here's a working fiddle: http://jsfiddle.net/mgLss/
Not sure why but when I add that directive to my application IT works fine, but anything else below it running angular fails and I get this error message:
Error: node is undefined
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3837
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3837
nodeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:4216
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3834
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3837
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3837
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3837
nodeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:4216
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3834
compositeLinkFn#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3837
compile/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:3746
bootstrap/</<#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:932
Scope.$eval#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:7808
Scope.$apply#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:7888
bootstrap/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:930
invoke#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:2788
bootstrap#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:929
angularInit#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:904
#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js:14397
f.Callbacks/o#http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js:2
f.Callbacks/p.fireWith#http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js:2
.ready#http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js:2
B#http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js:2
I've spent the last hour on IRC but cant get any acknowledgment of my question so here's hoping Stack will come to the rescue as it has so many times before.
This is something related to the plugin you are using, it manipulates the dom in a way angular does not like it, I didn't to go into the source code the point you to the root of the issue, to be honest. But here is a way (an ugly one) to fix it.
<div ng:controller="TestCtrl">
{{ hello }}
<div><taggable default="changed"></taggable></div>
</div>
​
Just wrap that directive within another DOM element, making sure the plugin is isolated.
http://jsfiddle.net/mgLss/33/
Building on #fastreload's answer, a slightly less ugly solution, which does not require changing your HTML:
// as per #fastreload, wrap input in a div to prevent Angular from getting confused
template: "<div><input type=\"text\"></div>",
link: function(scope, elm, attrs) {
elm.children().tagsInput({ // note children()
You should also include Angular last in your fiddle (under Manage Resources) (and in your code in general), then elm is automatically a wrapped jQuery element, rather than a wrapped Angular element, and hence we don't need to use $(elm) in the link function.

Categories

Resources