I have a rather simple select box in angular JS. I am trying to add a class to toggle/hide the individual elements. I have tried in various ways and I am simply not getting something about angular js.
<select ng-class="{hide: user.student == false}" class="btn-blockAddress" ng-model="docs.address.type" ng-options="t for t in consts.data.typeOfAddress"></select>
<select ng-class="{hide: user.student != false}" class="btn-blockAddress" ng-model="docs.address.type" ng-options="t for t in consts.data.typeOfAddressForStudent"></select>
This is not working for me. It disables one, and not the other select, but then when I change user.student, I expect them to swap, but there is no change.
Should I be defining the behavior of the DOM form some other location? I understood the purpose of angular js was to watch variables for change. I have based my code on similar use in other parts of the codebase.
How do I inspect the value of user.student at the point it is evaluated to decide the class?
The javascriptish statements that go in directives are not really javascript - so what is it?
I have found the docs for angular js pretty good to show specific use cases, but I can not find clear API info that I can lookup.
There is a plugin for the dev tools called Batarang that is life saving. Check out this video for usage.
Related
I asked a related question about this recently: Dojo _hasDropDown - How do I declaratively bind the properties?. However, I've been struggling with this problem for about 30 hours by now (20 of those before the last question), and I don't feel like I'm any closer. I'd normally edit the old question, but it would change the scope too much and invalidate existing answers.
My problem:
I have the following combobox and Memory store combined with a Struts2 request-scope servlet as part of machineOverview.jsp:
<div data-dojo-type="dojo/store/Memory"
data-dojo-id="machineNameStore"
data-dojo-props="<s:property value='%{getNameJsonString()}'/>"></div>
<s:set name="MachineName" value="machineSearchView.name"
scope="request"></s:set>
<div data-dojo-type="dijit/form/ComboBox"
data-dojo-props="store:machineNameStore, searchAttr:'name', value:'${MachineName}'"
name="machineSearchView.name" id="machineSearchView.name"></div>
I have this custom Dojo Widget in js/widgets/templates/ExpandableSearchComponent.html:
<div class="${baseClass}">
<div data-dojo-type="dijit/form/TextBox"
name="${SearchViewFieldName}TextBox"
class="${baseClass}TextBox"
data-dojo-props="placeholder:'${fieldName}'"></div>
<div class="${baseClass}Container" data-dojo-attach-point="containerNode"></div>
</div>
With this Javascript behind it in js/widgets/ExpandableSearchComponent.js:
/**
* Javascript for ExpandableSearchComponent
*/
define([ "dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin",
"dojo/text!./templates/ExpandableSearchComponent.html"],
function(declare, _WidgetBase, _TemplatedMixin, template) {
return declare("js/widgets/ExpandableSearchComponent", [ _WidgetBase,
_TemplatedMixin ], {
templateString : template,
SearchViewFieldName : "",
fieldName : ""
});
});
What I'm trying to do is essentially replace the first snippet with the below:
<div data-dojo-type="js/widgets/ExpandableSearchComponent"
data-dojo-props="SearchViewFieldName: 'machineSearchView.name', fieldName: 'Name:'">
<div data-dojo-type="dojo/store/Memory"
data-dojo-id="machineNameStore"
data-dojo-props="<s:property value='%{getNameJsonString()}'/>"></div>
<s:set name="MachineName" value="machineSearchView.name"
scope="request"></s:set>
<div data-dojo-type="dijit/form/ComboBox"
data-dojo-props="store:machineNameStore, searchAttr:'name', value:'${MachineName}'"
name="machineSearchView.name" id="machineSearchView.name"></div>
</div>
When this is done, it should just show a dijit/form/TextBox. When I click this Dijit Textbox, a dropdown should appear with in the dropdown the dojo/store/Memory and the dijit/form/ComboBox. Then, once the Combobox has had an option selected, both the Combobox and the dropdown should collapse again and the dijt/form/TextBox should show the value that was entered in the ComboBox, prefixed with the placeholder.
What I've tried:
I've tried a bunch of things:
I've tried binding _hasDropDown declaratively, which doesn't work.
I've tried binding it programmatically, during which I come into numerous problems with figuring out what to put in the define parameters, what to put in the function parameters, what to put in the declare parameters and what functions to return. I keep getting console errors in Chrome that are hard to figure out why they are happening, like my TextBox not being defined properly or my template Mixins not working properly,...
I've tried putting the original comboBox and Memory store into the widget directly, but I abandoned that path after 1 day because it was a fragile and complicated construction and it wasn't really what we wanted in the end either.
What I'm looking for:
I'm not looking for someone to implement this for me. I'm looking for a working example of using either dijit/_HasDropDown or dijit/popup used in a custom widget that includes:
The HTML of the widget;
The javascript code-behind of the widget;
How to use this widget in a page;
If necessary any related javascript for the page itself.
I've checked the Dojo documentation. There is no tutorial for either of the above dijit components. There is an API reference, but that only contains the Javascript, and even then just for how the API works.
The _HasDropDown Mixin API reference has the Javascript for how to add it to a widget, but not the HTML, and it shows how to create such a widget programmatically, but again without HTML code to explain what objects it is binding the widget to. It also uses Widgets, not a div, which I want to use for formatting reasons.
The dijit/popup API reference has the same issues as the _HasDropDown Mixin reference, meaning it shows the Javascript, but not the HTML or how to use it.
both of these API reference documents confuse me and I can't figure out how to implement them. I've also tried Googling, but most hits are for older versions of Dojo, from before the introduction of AMD modules.
As said a couple of times now, I can't figure out how to make these work. The documentation provided by Dojo explains part but not all of it and it's unclear to me how this all works. Can I even even use a widget in this manner? Will I have to write the textbox and the javascript to create the dropdowns directly into the source of my main page?
I'm hoping for a solution that allows me to just surround the element I want to convert with a div that has a data-dojo-type tag, so I have something semi-portable, but if that's not possible, I'll have to confer with my coworkers.
Clarification: I have read the sources for FilteringSelect, _HasDropDown, Select, ComboBox and some other Dojo components, but my big problem right now is that I can't figure out how they wire their dropDown to the right node.
Since you are looking for examples, have you checked the sources for the dijit widgets that use _HasDropDown? The documentation mentions Select, ComboBox, DropDownButton and DateTextBox. Their sources should give you a good sense for how to use the mixin, especially in conjunction with the reference pages explaining their use with programmatic and declarative examples.
For example the Select widget source: https://github.com/dojo/dijit/blob/1.10.6/form/Select.js and its reference page: http://dojotoolkit.org/reference-guide/1.10/dijit/form/Select.html
To make thing easier I suggest that you first refine the custom widget that must be dropped, programmaticaly place it as a normal widget and style it. It should then be very easy to use it as a drop down following the examples of the dijit widgets that use _HasDropDown.
Recently discovered document.registerElement
it seems nice that I can encapsulate bunch of HTML and JS code in an element.
How can I for example create an element that will be a bootstrap modal:
<bootstrap-modal>
<modal-header></modal-header>
<modal-body></modal-body>
</bootstrap-modal>
instead of inserting a lot of html that the modal requires.
And I would need one for dropdown :
<dropdown>
<option href=""></option>
</dropdown>
Is this good to declare elements like that?
If so, why this method is not in common use? In most websites I just see bunch of divs and spans with many classes..
Yes it is good to declare elements like that.
It's not in common use because most browsers don't implement it yet.
However there's a polyfill if you want to make them work in other browsers.
It will change soon because Custom Elements are now integrated in the HTLM Living Standards.
A good start to create your first custom element is to read this article about Custom Elements v1*.
*Note: the registerElement is being replaced by a new function called defineElement, you'll need at least Chrome v53 to make it work.
I have this website (in Hebrew): http://www.iping.co.il (if you could have a look at it maybe with google translate and see what it does it could be great but not a must).
It basically a website that shows your IP, and gives you a set of tools (like ping, whois check, open port checks...).
I've built it a while back and I was using jQuery and jQuery UI to do all the work (like opening dialogs, call the server, change the DOM, show a progress bar...).
Now I'm working on rebuilding it - I'm rebuilding using ASP.NET MVC 5, HTML5 and Bootstrap3. I figured it's a great little website to test new things I've been reading about lately. And one of those things I would like to try and implement (after reading much about) is AngularJS.
As far as I know, AngularJS is not meant to change the DOM directly, but use directives and 2 way bindings to do so.
I have a lot of code, and plugins that I use that uses jQuery and jQuery UI to (for example the dialogs, the progress bar and so on... things that I haven't figured out how to do with AngularJS). It seems that if I use the jQueryUI progress bar and update it from from AngularJS that I'm breaking some rules here and that it's probably dirty and not the way it should be written.
So my question is, what is the correct way to work when and build a rich UI when using AngularJS? is jQuery and jQueryUI even still relevant? if so, is there a correct way to use them (maybe DI somehow?)?
I've searched and found something called AngularJS UI - but it's not as rich as jQueryUI.
Thank you
Using plugins within directives is fairly simple in concept.
<div my-directive></div>
Following is a very minimialistic directive with just enough code to initialize a plugin. The returned function is equivalent to link in a more defined directive
angular.module('myApp').directive('myDirective',function(/* dependencies*/){
/* element is a jQuery object when jQuery is included in page before angular.js*/
return function(scope,element,attrs){
/* can use attributes or scope to pass options to plugin if needed*/
element.someJqueryPlugin();
}
});
This would be equivalent to writing in jQuery only:
$(function(){
$('[my-directive]').someJqueryPlugin();
});
If you want to use AngularJS and Bootstrap I suggest you take a look at these directives:
http://angular-ui.github.io/bootstrap/
Once you load the modules, you can set up say a progress bar this way:
<progressbar max="max" value="dynamic">
<span style="color:black; white-space:nowrap;">{{dynamic}} / {{max}}</span>
</progressbar>
You shouldn't even need to include JQuery if you only need the Bootstrap components.
Angular provides us with a mechanism to write directives - which is extremely powerful in what it can do. But the thing I keep wondering is - in what scenario should you be actually writing a custom directive of your own.
We keep seeing questions in and around Stack Overflow with various people attempting to write directives which ( in my opinion ) need not be written in the first place. In most cases they can be solved with a combination of repeat, switch and show. See examples of questions containing directives that I think shouldnt be directives in the first place!
https://stackoverflow.com/questions/16101073/angularjs-directive-is-not-working-in-ie-10
Fire button click in AngularJS
angularjs: using a directive inside the ui-bootstrap modal
Some examples scenarios. I am not picking on them in anyway..because I am sure it is not clear to anyone when we should be using / writing a directive.
We see scenario's where people use directives as a mechanism for templating. Is this the right way of doing things? Or is there a better way? ( ng-include perhaps? ) Are there any upsides / downsides to using directives as a templating mechanism? The reason for this question is that sometimes I wonder if people write directives because coming from the jquery world the first thing they can think of is writing DOM manipulating code and since the Angular way is to not manipulate the DOM in controllers it all gravitates towards writing all that code in a directive.
EDIT :
I believe this confusion ( of shoving things inside a directive ) arises because Angular does not have a separate concept of a "view" - unlike Backbone ( which only has a "view" but no component! ). Directives are amazing at defining components - But I think if you use them to create "views", you will lose some of the "angular" way. This is my opinion though -which is why I am soliciting what the rest of the angular community thinks.
The good thing about simpler directives ( directives that do just 1 thing! ) is that they are absolutely easy to test. If you look at all the ng directives they all do 1 thing and do that thing pretty well.
What is the best way of defining reusable "views" ( not components! ) in Angular ? Should that be written in a directive? Or is there a better way?
It would be awesome if one of the Angular Dev's have an opinion in this matter!
Well... quite a good question.
I believe directives are mainly meant to "extending HTML so you can build a DSL", improving productivity and code quality.
The question is that this is achieved through componentizing things. But it is of most importance that we understand that directive is not about visual components only, neither templating only, but also, about behavior.
To summarize, using directives you could:
create a DSL to augment elements behavior
create DSL widgets, so you can stop repeating yourself
wrapping already existent components, buying you productivity.
optimization
Augmenting behavior is nothing more than componentizing behavior. ng-click, for example, adds the clickable behavior to any element. Imagine you're creating an app with dozens of draggable elements. Than you would create a directive to augment element behavior, making it draggable without even touching the element visual (<span draggable>Test</span>). Yet another example, imagine you gonna have special hints on mouse hover. title attribute is not suitable to this, then you can create your own my-title attribute, that automatically create your "special hint" on mouse hover (<span my-title="Some caption">Test</span>).
And when developing an app, you have a plenty of domain specific concepts and behaviors. Stackoverflow, for example, have a strong concept of voting. You can vote up/down questions, answers, comments... So you could create a reusable votable directive, that would add "vote behavior" and "vote widget" (up/down arrows) to praticaly any element.
This last one gives us another face: templating. Not only for lazy ones, but to improve code quality and maintainability following DRY principle. If you are repeating controllers code, HTML structure, or anything else, why not templating and componentizing it, right? Directive is your guy for this job.
Of course, you also have some generic application of directives. Many application (not to say all of them) rely on clickable elements, this is why we have a ng-click, for example. Many applications have upload areas. And what would you do in a jQuery way of thinking? You would create a jQuery plugin. Right? In Angular, you would create a Angular Widget (using directives). You could even wrap an already existing plugin using a directive, and, once more, augmenting its behavior so it can smoothly talk to your application.
Regarding wrapping plugins, to every jQuery plugin (but could be MooTools, Ext...), you gonna have to create a controller, call $('element').plugin() on it, and caring that jQuery events change and $digest your scope for you. This is another perfect use of directive. You can create a directive that apply .plugin() on your element, listening to the events and changing/digesting your scope for you. This is what Angular UI Project is all about, take a look.
One last point is the optimization. I recently created and app that creates tables with dynamic columns and rows (a grid). The question is that data is updated in real time! And the ng-repeat inside ng-repeat, to create headers, was killing application performance (nested loops in every $apply cycle, happening each half second). So you can create a directive that create the columns template and still use ng-repeat inside it, but you would have a loop through columns only upon columns edition.
So, wrapping up, I believe directives are about componentizing behavior and form (templating), which buy you producitivity and code quality.
I personally write directives quite a lot, as they tend to make my program much more declarative.
An example: in a JSON -> HTML form parser I made recently, I created a "form-element" directive, that parses the JSON element a creating the necessary directives as it's children. That way I have a directive for each field type, with specific behavior and methods. Also, any common behavior shared between all elements is in the form-element directive.
This way, a group element is a directive with a ng-repeat in it's template, and a title element is as simple as a h1. But all can have the same conditional behavior (a group can only appear if a previous field has a certain value set, for instance). And all extremely clean - any time i need to add/change, it all stays perfectly put, and the html is extremely declarative.
EDIT - included a snippet of code, as requested via comments.
/**
* Form Element
* ============
*
* Handles different elements:
* Assigns diferent directives according to the element type
* Instanstiates and maintains the active property on the formElem
*/
.directive("formElement", ['$compile', function($compile){
return{
restrict: "E",
scope:{formElemModel: '='},
link: function(scope, element, attrs){
var template = '';
var type = scope.formElem.type;
switch (type){
case "field":
template =
"<form-field-"+scope.formElemModel.fieldType+" ng-switch-when='true'>\
</form-field-"+scope.formElemModel.fieldType+">";
break;
default:
template = "<form-"+type+" ng-switch-when='true' ></form-"+type+">";
break;
}
element.html(template);
$compile(element.contents())(scope);
// Active state of form Element
scope.formElem.active = true;
scope.testActive = function(){
if(scope.$parent.formElem && scope.$parent.formElem.active == false){
scope.formElem.active = false;
}
else{
scope.formElem.active =
scope.meetsRequirements(scope.formElem.requirements);
}
}
scope.$watch("meetsRequirements(formElem.requirements)", scope.testActive);
scope.$watch("$parent.formElem.active", scope.testActive);
}
}
}])
What is the best way to bind Javascript events to my custom MVC controls? My initial thought is to create the controls using Html Helpers which give them a CSS class that signifies what kind of control they are. Then, on document.ready, I'll use jQuery to select all such controls by their class name and bind their events.
However, I'm concerned about the speed of selecting from the entire dom by class name. I've read (and experienced) how slow this can be, especially in IE8 which we need to target for this project.
I could select by IDs by creating a js file for each page, but I'd rather not do this, as it's a complicated web app with lots of pages. I'd rather have one js file for each type of control that gets included in a view if the view contains at least one of that type of control.
Are CSS classes my best option? Any other ideas? I'm using MVC3.
My advice would be to try it out with classes and test the performance. If you are not satisfied, switch to IDs. I use class selectors all the time and don't find them terribly slow in any browser. When you give jquery a context to search in, things are quite fast. For example:
$('#controls .control').whatever();
Or
$('.control', '#controls').whatever();
Sizzle is great at optimizing these things to be fast.
Edit: Here is a good reference for jQuery performance tips in general (notice #5):
http://net.tutsplus.com/tutorials/javascript-ajax/10-ways-to-instantly-increase-your-jquery-performance/