How to set attribute values for Backbone views? - backbone.js

I am building a Marionette item view, which is an a element.
I wonder how I can get valid a element with Mationette, because the code I have doesn't set the href attribute:
class CategoryFilters.ItemView extends App.Views.ItemView
tagName: "a"
className: "btn btn-primary"
template: "topics/categoryFilter/filter-item"
triggers:
"click": "filter:clicked"
that gives the result :
<a class="btn btn-primary">company</a>
it looks ok, but this a tag doesn't have href attribute.
How can I set href="#" on this view in a clean way?

You could use the attributes property, like...
attributes: { href: '#' }

Related

ng-repeat and polymorphic directive

I'm wondering if there is a way to build a custom Element directive to use with ng-repeat in this way:
<div class="list">
<my-custom-directive class="item item-icon-right" ng-repeat="a in concepts">
<p>{{::a.label}}</p>
<i class="icon ion-forward muted"></i>
</my-custom-directive>
</div>
my-custom-directive should compile itself in an anchor if a.href exists, in a paragraph if it doesn't.
The problem basically is merely design: I have some items which doesn't have an href, but they should still be in the list. In Ionic1 it looks like I can do a div list or an a list, but not mixing up without breaking the list design..
Sure you can. Something like this:
<my-custom-dir ng-repeat="a in concepts"></my-custom-dir>
where, directive is like,
app.directive('myCustomDir', function() {
return {
restrict: 'E',
templateUrl: 'custom.html'
}
})
And, the custom.html template,
<p ng-hide="a.href">{{::a.label}}</p>
<a ng-href="{{a.href}}" ng-show="a.href">{{::a.label}}</a>
<i class="icon ion-forward muted"></i>
Also, I kept the $scope.concepts to have dummy object as follows,
$scope.concepts = [{
href: 'eample.com',
label: 'example'
}, {
label: 'example1'
}, {
href: 'eample2.com',
label: 'example2'
}]
working example
Although, I think you should be able to have a div.item with ng-repeat inside your .list. And in the div.item you should be able to have whatever you want (not sure how ionic1 deals with that though)

Can I not use $ctrl. in angular component template

I am using angular 1.5 and I wanted to extract part of my DOM into a component.
Here is what I have done so far:
angular.module('my-app').component("menuItem",{
templateUrl : "lib/menu-item.tmpl.html",
bindings : {
index : "<",
first : "<",
last : "<",
item : "=",
onDelete : "&",
onMoveUp : "&",
onMoveDown : "&"
},
controller : function($scope) {
}
});
And the template looks like so:
<div>
<aside class="sort-buttons">
<ul>
<li>
<button ng-click="$ctrl.onMoveUp({index : $ctrl.index})"
ng-disabled="$ctrl.first">
<i class="icon icon-up"></i>
</button>
</li>
<li>
<button ng-click="$ctrl.onMoveDown({index : $ctrl.index})"
ng-disabled="$ctrl.last">
<i class="icon icon-down"></i>
</button>
</li>
</ul>
</aside>
<div class="row">
<button class="btn btn-danger btn-icon btn-remove"
ng-click="$ctrl.onDelete({index : $ctrl.index})">
<i class="icon icon-remove"></i>
</button>
</div>
</div>
I use this component (far from finished!) like so:
<section class="container menu">
<menu-item index="$index" first="$first" last="$last" item="item"
on-delete="removeItem(index)"
on-move-up="moveItemUp(index)"
on-move-down="moveItemDown(index)"
ng-repeat="item in menu">
</menu-item>
<!-- some other display details of `$ctrl.item` -->
</section>
I have three main questions I guess:
Why do I have to use $ctrl everywhere in my template? There is $scope so why all the bindings go to $ctrl rather than $scope? And is there a way to change this?
Can I somehow have values like $index, $first and $last passed in? It seems to me like it is a "buttery butter" to pass them in...
Is this even the right approach? Or should I use directive? I know components have isolated scope, and directives can have not-isolated scope. but could I mix/match in a directive (share the scope with controller, but also add my own functions to be used within directive/template only?)
Thanks for your help.
Why do I have to use $ctrl everywhere in my template? There is $scope
so why all the bindings go to $ctrl rather than $scope? And is there a
way to change this?
$scope will disappear with angular 2.0. You are not obliged to use $ctrl. I recommend that you still use "controllerAs" with a named controller, in order to avoid confusion inside your templates.
controllerAs: "menuItemCtrl",
controller : function($scope) {
},
and then :
<button ng-click="menuItemCtrl.onMoveUp({index : menuItemCtrl.index})"
ng-disabled="menuItemCtrl.first">
<i class="icon icon-up"></i>
</button>
to use your bounded variables inside your controller, you have to use this :
controller : function() {
var self = this;
// self.index contains your index
}
Can I somehow have values like $index, $first and $last passed in? It
seems to me like it is a "buttery butter" to pass them in...
I don't really understand how you want them to be passed.
Is this even the right approach? Or should I use directive?
When you're facing an application that can be displayed as a tree of components, components are the best option.

angularjs how to trigger changes on object in scope

I have the $scope object (array of objects) like this
$scope.parts = [];
(content of $scope.parts is changing during 'run-time', not just filled once per page load)
Later, it some custom directive i show those parts in such manner:
<li ng-repeat="part in parts">
<span>{{part.name}}
<i class="fa fa-check"
tooltip="some tooltip"
...
</i>
</span>
</li>
According to some logic, i want to change 'fa-' class and tooltip text.
I can do it like this
<i class="fa"
ng-class="haveDescr(part.name)"
//and in directive's controller
$scope.haveDescr = function (partName) {
return someCondition ? 'fa-check' : 'fa-question-circle';
};
and so on for the tooltip, and... for every attribute i want to change?
Is there a better way, than to write a scope "check-function" for every attribute? How can i trigger changes in every single part/property of $scope.parts and do the DOM changes described above? What is the right "angular way" for this? Or, maybe it is possible to 'intercept' ng-repeat action and do everything there?
You can use ng-class with an 'object' expression.
<i class="fa" ng-class="{'fa-check' : part.name, 'fa-question-circle' : !part.name}">
You can use ng-class and title
<i ng-class="{'fa-check':showFaCheck(part.name), 'fa-question': !showFaCheck(part.name) }" title="{{getTooltip(part.name)}}"/>
Fiddle http://jsfiddle.net/4PYZa/303/

Conditionally adding data-attribute in Angular directive template

I'm working on the template for a directive. If a property in the scope is set to true, data-toggle="dropdown" should be appended to the element. If the variable is false, this data attribute should not render as an attribute of the element.
For example, if scope variable is true, the template should render:
<span data-toggle="dropdown"></span>
If false, the template should render:
<span></span>
What would the template look like to accomplish this?
For example, I know that I can use ng-class to conditionally include a class. If I want the template to render this:
<span class="dropdown"></span>
Then my template would look like this:
"<span ng-class="{ 'dropdown': isDropDown }"></span>
If scope variable isDropDown is false, then the template will simply render:
<span></span>
So there's a way in a template to conditionally add a class="dropdown". Is there a syntax for templates that allows me to conditionally add data-toggle="dropdown"?
One of the things I've tried for the template is:
"<span data-toggle="{ 'dropdown': isDropDown }"></span>
My thinking with the above template is that if the scope variable isDropDown is true, the value of data-toggle will be set to "dropdown". If isDropDown is false, then the value of data-toggle would simply be an empty string "". That doesn't seem to work though.
I think a good way could be to use ng-attr- followed by the expression you want to evaluate.
In your case it would be something like:
<span ng-attr-data-toggle="{{ isValueTrue ? 'toggle' : 'notToggle' }}"></span>
Here's a fiddle with an example.
<span ng-attr-data-toggle="{{isTrue && 'dropdown' || undefined }}"></span>
will produce when isTrue=true :
<span data-toggle="dropdown"></span>
and when isTrue=false :
<span></span>
At the moment, there is no angular directive that allows you to remove or add an attribute conditionally. You can do ng-switch around the span, one with that attr and another one without it.
<div ng-switch on="condition">
<span data-toggle="dropdown" ng-switch-when="value"></span>
<span ng-switch-default></span>
</div>
or
<span data-toggle="dropdown" ng-if="expression"></span>
<span ng-if="!expression"></span>
You can also create a directive for that same purpose (adding/removing attrs conditionally) but that would be a bit more complicated.
Additionally if what you want is manage the scope variable inside the directive you can pass it as another attribute.
Example:
<span data-toggle="dropdown" when="isDropDown"></span>

Backbone.js - How to use 'ul' 'li' tags as tab widget using MVC?

The question may confuse you, I want to achieve the 'tab' widget from 'ul' and 'li' tags using 'Backbone.js' and it's MVC concept. How to do?
For example
<ul>
<li> One </li>
<li> Two </li>
<li> Three </li>
</ul>
When the link 'one' is clicked then I want to show some content (div) and want to hide others how to do using MVC concept ?
This could be done without Backbone and MVC, but I want to do this with Backbone, please help me.
You can create a Backbone.View that will handle all of your "tabs". This Backbone.View should cover the or whatever is above your content.
Based on your ul, you can add CSS selectors or other attributes:
<div id="mainDiv">
<ul>
<li class="tab-one">One</li>
<li class="tab-two">Two</li>
<li class="tab-three">Threeli>
</ul>
<div id="tab1" class="tab">...</div>
<div id="tab2" class="tab">...</div>
<div id="tab3" class="tab">...</div>
</div>
Create a Backbone.View to handle the page events:
MyView = Backbone.View.extend({
el: $('#mainDiv'),
events: {
'click .tab-one': 'showTabOne',
'click .tab-two': 'showTabTwo',
'click .tab-three': 'showTabThree'
},
showTabOne: function() {
$(this.el).find('.tab').hide();
$(this.el).find('#tab1').show();
},
showTabTwo: function() {
$(this.el).find('.tab').hide();
$(this.el).find('#tab2').show();
},
showTabThree: function() {
$(this.el).find('.tab').hide();
$(this.el).find('#tab3').show();
}
...
}
This is just to show and hide tabs using Backbone. You can do a lot more with Backbone :)
Edit: If you're tab list is dynamic, you can put the initialization of events using jquery way inside the Backbone.View's initialize() function. This will get invoked once you instantiate a Backbone.View (var view = new MyView;)

Resources