For example, I need to disable every input when the view's model isn't new (has an id).
I can do :
if(!view.model.isNew()) {
view.$('input, select, textarea').prop('disabled', true);
}
or I can go do an "if" on every input I have in my template:
<input type="text" {{# if model.id }}disabled{{/ if }}/>
If we follow the MVC (or MVP) pattern, I guess the second approach would be best, since the view logic is in the view. However, if I go with this approach and decide to change the condition that disables the inputs, I need to change it for every input in EVERY template. If I leave in the JS code, there is only one place to change.
This is just one example, but I am having similar dilemmas with alot of things. Hopefully you got an answer for that.
Cheers!
Based on your question, I'd say that you're probably running into this general problem for two related reasons -
You're using backbone exclusively, rather than a framework like Marionette or Chaplin.
Your views are "too big" and trying to incorporate too much material into a single view.
I almost never include logic into templates and that's because I almost never need to. That's because I write a lot of very small views, and piece them together to make large views. Marionette's view classes make this very easy to do, by subclassing the backbone view into different view types, adding additional utilities and drastically cutting down on boilerplate. Marionette is also very good at handling nested views, which really allow you to drill down and create the exact view tool you need for a specific use case.
It's not at all uncommon to be able to define a useful view using Marionette in 1-2 lines of code, which gives you a lot of flexibility to make very small, efficient views. The disadvantage to making lots of small views is that it's a lot of code to write, and could become difficult to maintain, but Marionette makes that disadvantage relatively insignificant. Marionette only took me a couple of days to get the hang of, and I highly recommend integrating it into your Backbone apps for exactly this problem.
When your views are big, and try to do too much, you wind up with the problem you're describing - you have to modify them too much to fit your specific needs and your code gets ugly and hard to read. When you have a lot of small views, they're very responsive and need little if any customization.
The example from your question is, I think, a border line case. My gut instinct would be to create two entirely separate views and run them under the following pseudo code:
editableView = { //definition }}
disabledView = { //definition }}
if (newModel)
editableView.render()
else
disabledView.render()
This is my gut instinct because my bet is that there are other differences between the views than whether the inputs are editable. Even if there aren't now, you may find in a few months that your needs have changed and that you'd like to incorporate some changes. The approach I suggest allows you to put those changes right into the appropriate View and not have to worry about logicking them out in a single view and deciding whether that logic belongs in the template or the view.
If you were absolutely certain that the only difference between the two views was going to be whether the inputs were editable, and that your needs are not going to change in the future, then maybe you would want to think about rendering them with the same view. If that is the case, I'd recommend that you put the logic in the javascript, rather than in the template, for the reasons you identified. But as I said, your example really is a borderline case, and in most instances I think you'll find that shrinking your view scope will really help you to see where your "template logic" belongs.
NOTE: I've talked a lot about Marionette in this answer, but I also mentioned Chaplin as another option above. I don't have much experience with Chaplin, but you may want to consider it at it as a Marionette alternative.
I prefer to do implement view logic in templates:
It is easier to change and read
Any dependency to id, element and etc can be implemented in template
List item
complex logic can be implemented in templateHelper of marionette or serializeData of Backbone without any dependencies to content of template or view
you can also implement complex logic using Handlebar Helper
Disadvantages of view logic in code are:
in case of changes to selectors (id, classes and so), all views have to be changed or reviewed
logic has to be applied again if view is re-rendered
Perhaps what you might be looking for presenter (aka decorator).
Instead of sending the template the model directly, consider sending it though a presenter, this way you can construct the attributes for the input field. Something like this:
present = function(model) {
return {
inputAttributes: model.isNew() ? 'disabled' : '',
id: model.id,
name: 'Foobar'
}
}
template(present(model));
then in your template:
<input type="text" {{inputAttributes}}>
Related
I am making something similar to sheet with cells where using drag and drop i can move events, that are components, around.
Since it is possible to add component from any file like this
import event from "event.vue"
let el = document.getElementById("div")
const newComponent = createApp(event)
newComponent.mount(el)
Im trying to remove it somehow aswell, but i had no luck to find solution.
i have tried to this
let element = document.getElementById("newComponent")
element.parentNode.removeChild(element)
It's kind of working, but i can't add new component to same div because there is dataset remaining 'data-v-app' and i guess its because old component was not removed. Is there a way to do this or maybe vue isn't capable?
v-if is still the "official" way of doing things here because it uses Vue's reactivity.
Modifying the DOM is not recommended since it's imperative, like jQuery: you need to tell the language how to do things, so you need to take care of finding the selector, ask it to do things on it, and loop that process in case of an event listener or alike.
VueJS is declarative, so the API is far less complex. You tell what variable is bind to what and when the variable mutate, it will react accordingly to the changes without you needing to tell step by step what to do.
When you project grows, an imperative approach like jQuery or your vanilla JS (document.getElementById) will not be efficient because you will need to describe everything that happens once you mutate a variable. If 12 things depend on a thing, you will need pretty much the double of lines of code for each of them.
While in Vue, you will make some conditions thanks to the API and it will make those changes by itself. The complexity is then greatly reduced. On top of having powerful directives + Vue devtools to help you.
Add to that the fact that if you mix both some Vue state + imperative coding, you will have the worst of 2 worlds. You will need to do funky things to kinda keep the reactivity + will still need to write declarative code.
Hence why, people are using Vue's API + template refs only when needed.
Stay away from imperative coding: jQuery, manually selecting DOM elements etc...you will have an easier time, less complexity and more performance by far.
Vue/React exist for a reason, mainly removing complexity. Use them to their full potential.
I am thinking of making a web app and was contemplating using dojox/app to do it.
I would prefer to use a more programmatic approach to dojo but it seems dojox/app is mostly declarative.
After some searching I found an archive basically asking the same question I have
http://dojo-toolkit.33424.n3.nabble.com/Questions-about-dojox-app-design-td3988709.html
Hay guys,
I've been looking at the livedocs for dojox.app and while it seems quite cool I >have to say some stuff isn't clear to me.
Specifically, is the "template" property of views - specifying an html file - a >must or optional?
This was in 2012.
Since then I have found the customeApp test in the examples in the documentation which seems to show basic programmatic views in dojox/app however I am having some difficulty understanding it.
I would like to create the different views of my app like this
require([
"dojo/dom",
"dojo/ready",
"dojox/mobile/Heading",
"dojox/mobile/ToolBarButton"
], function(dom, ready, Heading, ToolBarButton){
ready(function(){
var heading = new Heading({
id: "viewHeading",
label: "World Clock"
});
heading.addChild(new ToolBarButton({label:"Edit"}));
var tb = new ToolBarButton({
icon:"mblDomButtonWhitePlus",
style:"float:right;"
});
tb.on("click", function(){ console.log('+ was clicked'); });
heading.addChild(tb);
heading.placeAt(document.body);
heading.startup();
});
});
but I can only find examples like this
<div data-dojo-type="dojox/mobile/Heading" data-dojo-props='label:"World Clock"'>
<span data-dojo-type="dojox/mobile/ToolBarButton">Edit</span>
<span data-dojo-type="dojox/mobile/ToolBarButton"
data-dojo-props='icon:"mblDomButtonWhitePlus"'
style="float:right;" onclick="console.log('+ was clicked')"></span>
</div>
Is there a way to go about this programmatically or somewhere I can find some clarification on whats happening here https://github.com/dmachi/dojox_application/tree/master/tests/customApp
Absolutely. I have been creating them programmatically for a long time and believe it is far superior way than templating. Difficulty in tackling a framework is knowing keywords to search for. Your answer, I believe, can be found by learning Dojo WidgetBase, and anything else that uses the word "Widget".
Good start is here http://dojotoolkit.org/reference-guide/1.10/quickstart/writingWidgets.html . To successfully work with Dojo Widgets you will also need:
concept of a LifeCycle http://dojotoolkit.org/reference-guide/1.10/dijit/_WidgetBase.html#id5. Lifecycle injection points will allow you to modify DOM tree of the template using JavaScript native API so you do not have to use data-dojo in attributes all over. You will capture nodes as private class properties during buildRendering phase so you can apply constructor parameters to them passed during instantiation in the parent. Finally, you will return the final DOM in postCreate() or startup(), depending on whether you need to specially handle child components or not.
concept of Evented http://dojotoolkit.org/reference-guide/1.10/dojo/Evented.html . This is what you need to do widgetInstance.on("someEvent", eventHandler) programmatically
Only custom attribute I use within an HTML tags of templateString is data-dojo-attach-point and data-dojo-attach-event. These are very convenient, saving lots of time and makes data binding less bug prone, to automatically connect widget's class properties with values in the tag. Although you can do those programmatically too with innerHTML, the amount of tedious boilerplate code in my opinion is not worth the effort.
Go through that tutorial and if by end you do not understand something do let me know and I will elaborate (I am not the type who just sends askers away on a link and not bother elaborate on the material).
I have just started with backbone... I was excited about it until I ran into a something quite confusing. So with what I have seen while searching for backbone info is that a view is basically unique to one element.
Example project: Web page builder / editor
So reguarding the example project I am guessing that you will have a view Element() with methods that would do some of the following
Change CSS styles
Change text of element
Remove element
Add Class to element
Change by (id, class)
and in those methods they would do something like
this.el.style.color = 'red';
The only way I thought for this to be possible is to create a new Element({el: someElement}) for each element that is being changed.
So say you have 100+ elements on a page and 100+ views, that just wouldn't seem right to me.
If the questions confusing that's because I'm Confused so if you need any more info. comment...
Also I can't seem to work out where Models would come into a application like this because most of the info I have read about them is that they are used to contact the server, whereas in this case. that would only be when the page is saved.
So, is it Normal to have so many views?
In my experience, the short answer is yes, that is fairly normal.
Generally in the sophisticated web applications in Backbone I have seen, it is certainly fairly common to have a few dozen views in the viewport. For example, a handful of views for the header, navigation, footer, and then maybe showing a dozen or so models, but each model is represented by a handful of views.
#mu's comment makes a good point that at some point maybe you need to just simplify your application's UI. But yes, if you are working on some sort of WYSIWYG style live web page editor, expect the order of magnitude of live view instances in the hundreds.
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);
}
}
}])
A simple javascript widget design question.
I have started working in javascript fairly recently. And as part of my work, I intend to create a lot of reusable code; so for me javascript widgets seems like the best way to go.
However I am faced with a design dilemma, and I am not able to find the right answer.
I have a simple javascript widget, which alters the string in a html component. So my widget is somewhat like this:
(function() {
var convertString = function() {
$(".classForHtmlComponentsIWantToHandle").each(function(index, element) {
//js_fu stuff done with string fetched from "element"
});
};
var _somePrivateHelperMethod() {
//some work that would have been impossible without this helper method
};
GloballyDefinedNamespace.StringUtils = {convert : convertString};
}());
this allows me to call later
GloballyDefinedNamespace.StringUtils.convert();
Now if you would notice in my widget-ish function above, I extract all the HTML components from the DOM, that I want to alter string for. Interesting bit is that HTML will have span and divs with same css class and also textbox components with css class.
Both have a different way of extracting their value and setting new value back.
Based on my experience, if this is a widget to alter string then all it should care about is incoming object that "hold" string in a uniform manner and then based on a object expectations, my widget should be able to operate blindly.
"if it sounds like a duck, walks like a duck, then it's a duck". Kind of thing.
So effectively I would like to be able to NOT worry about distinguishing "element" object being a textbox or span in my widget. Instead wrap it into a generic wrapper.
However people have advised me that in javascript widgets the usual convention is to take care of component specific stuff within widgets. I am not convinced, as I firmly believe in programming to interfaces and not specifics. So I am at conflict.
In my example above, I don't think so the highlighted dilemma does justice to this problem, but on a larger scale this pops up as a question for me often.
I would like to hear opinion from guys, as to how to build that component independence within my widget for an HTML DOM? Is a solution to create javascript wrapper objects with same interface and then css-select them separately and then make method call as following?
(function() {
var locateAllComponents = function() {
$(".generic-class").each(function(index, element) {
//wrap element into suitable wrapper that has common interface for getter
//setter.
GloballyDefinedNamespace.StringUtils.convert(wrappedElement);
});
};
}())
Any insights and answers would be highly appreciated.
You are trying to force concepts on javascript that are foreign to it.
Programming to an interface works for for OOP, but for other language types it is a bad idea.
You can look at how jquery uses .text() (http://api.jquery.com/text/) and .val() (http://api.jquery.com/val/) and you will see that what you want to abstract they put into two different functions, for a reason.
Widgets can be useful, but at a cost of bloat and performance, so you need to look at what you are doing and ensure that you don't exact too much of a price.
So, start small, perhaps with a widget that can work on form elements, and see what you can do reasonably within the object, but you will find that at some point it becomes very helpful if either the API user or the API developer creates functions to pass in to your widget, to get the additional functionality.
But, all of this will impact performance, so as you work, do some unit tests so you can look at changes in performance to help guide you on what changes are worth the price.
You may want to start with looking at the JQuery UI widgets though, and see what they did, rather than just re-inventing the wheel for no reason.