Backbone.js Task App how should grouped view look like - backbone.js

I am developing a task app in Backbone.js for FUN and one of feature is grouped view. Grouped view will display tasks that are grouped according to their done status. Currently i can construct the grouped object from the collection. Constructing the view has become trivial to me. Here is a snapshot of how i want the view to look like
Completed Tasks
- Water the Garden
- Clean my closet
Pending Tasks
- Watch Whose line is it anyway
the JSON after grouping is below
{
"true": [{
"Name": "Finished Demo",
"Done": true,
"id": "4b3d8d3d-637c-fd5d-034b-b275b5f00e05"
}, {
"Name": "This is a new task",
"Done": true,
"id": "db5b379f-6f96-346d-4945-baf2d5ac0c76"
}, {
"Name": "Clean the closet",
"Done": true,
"id": "3b5091e5-a8df-845b-3c6d-2185187eb456"
}],
"false": [{
"Name": "Edited another new task",
"Done": false,
"id": "0ee399b2-8fd9-84f2-735e-902d09c625a1"
}]
}
I can't think of how to construct a template for the UI based on grouped json above. Assuming i am using underscore.js _.template for templating purpose.
How should the template look

Keep in mind, true and false are reserved keywords in Javascript. I suggest you don't use it as variable names.
<ul>
<% if (finished) { %>
<% _.each(finished, function (task) { %>
<li id=<%= task.id %>>
<%= task.Name %>
<input type="checkbox" checked />
</li>
<% }); %>
<% }; %>
<% if (unfinished) { %>
<% _.each(unfinished, function (task) { %>
<li id=<%= task.id %>>
<%= task.Name %>
<input type="checkbox" />
</li>
<% }); %>
<% }; %>
</ul>
http://jsfiddle.net/theotheo/zJXW8/

Related

ng-repeat not displaying the individual items

When running the code below in my angular 1.x app I can see the first line returns the following :
[ { "id": 121, "valid": true }, { "id": 123431, "valid": false } ]
However when I try to display the valid or id property in the ng-repeat on the following line I see nothing whatsoever? What am i doing wrong??
{{ allItems | json }}
<div ng-repeat="item in allItems">
{{ item.valid }}
</div>

Getting Nested values in angular with a json feed

I have the following json example:
posts: [
{
title: Post Title,
- cat: [
- {
name: "Category Name",
}
],
I am able to get the title in Angular using {{post.title}}
However when I try to get {{post.cat.name}} its not working and its returning "0"
That's because cat is an array. You should handle it like that.
{{posts.cat[0].name}} if you want the first element in that array.
Usually for arrays you'll use ng-repeat though:
<span ng-repeat="cat in posts.cat">{{cat.name}}</span>
try this.
var app = angular.module("app",[]);
app.controller("MyCtrl" , function($scope){
$scope.posts=[
{
title: "Post Title",
cat: [
{
name: "Category Name",
}
]
},
{
title: "Post Title2",
cat: [
{
name: "Category Name2",
}
]
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MyCtrl">
<table>
<tr ng-repeat="p in posts" >
<td >{{p.title}}</td>
<td >{{p.cat[0].name}}</td>
</tr>
</table>
</div>
cat is an array, so to get the name of the first object in that array, you would have to use:
{{post.cat[0].name}}

AngularJS ng-repeat only for Items with a Specific Subfield

How can I get ng-repeat to only repeat items which contain subfields? I have a list of videos that updates based on language preference. I want to do something like ng-repeat="video in videos" only where ng-show="video.title[videoLanguage]" would make the element show. When I try using ng-show, it works somewhat but I have other code that works based on the length of the videos list (which updates since not all the videos are available in every single language).
Here's my code:
<ul ng-init="select=0" ng-style="{'margin-top': ((videoContainerHeight - (videos.length * 160)) / (videos.length - 1)) * select}">
<li ng-repeat="video in videos" ng-class="{'selected': select == $index}" ng-click="$parent.select=$index; changeNextPage(video.url);">
<div class="thumbnail"></div>
<div class="title">
<div class="title-cell">
<h2 ng-bind="video.title[videoLanguage]"></h2>
</div>
</div>
</li>
</ul>
Videos list object:
{
"id": "videos",
"url": "/videos",
"view": "views/videos.html",
"nextPage": "#/home",
"videos": [{
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "Short Title"
}
}, {
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "Longer Title Here",
"spanish": "Hi"
}
}, {
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "This is a Really Really Really Long Title",
"spanish": "Hi"
}
}, {
"url": "#/videos/extraction",
"thumbnail": "img/thumbnails/thumbnail.jpg",
"title": {
"english": "Short Title",
"spanish": "Hi"
}
}]
}
I'm looking to have ng-repeat generate a 4 item list when the language is set to english and a 3 item list when the language is set to Spanish.
I have created a fiddle , I think this is exactly what you want, ahve a look
https://jsbin.com/dinuku/edit?html,js,output
I created a filter to filter items based on language
app.filter('languageFilter', function() {
return function(array, lang) {
return (array || []).filter(function(item) {
if (lang in item.title) {
return true;
}
return false;
});
};
});
I suggested you the ng-switch
ng-switch doc

Advanced filtering with AngularJS

I'm looking to filter the following list with AngularJS by both category and location. The difficulty I'm having is being able to properly nest the results beneath their respective categories (see below) after the filtering has occurred.
var jobs = [
{
title: "Software Engineer",
category: "Engineering",
location: "New York"
},
{
title: "Web Developer",
category: "Engineering",
location: "Chicago"
},
{
title: "UX Designer",
category: "Design",
location: "New York"
}
]
This is the desired output (also note the alphabetically ordered categories):
Design
UX Designer
Engineering
Software Engineer
Web Developer
Any help would be much appreciated. Thanks!
Here is a working example with your data on plnkr using the filter solution from AngularJS Group By Directive without External Dependencies:
http://plnkr.co/edit/w5UJUN?p=preview
Do you have something like this in your mind:
<b>Design</b>
<ul>
<li ng-repeat="job in jobs | filter: { category:'Design'}">
{{job.title}}
</li>
</ul>
<b>Engineering</b>
<ul>
<li ng-repeat="job in jobs | filter: { category:'Engineering'}">
{{job.title}}
</li>
</ul>
There is working JSFiddle.
I would re-structure my JSON as follows:
$scope.parsedJobs = [];
angular.forEach($scope.jobs, function(value, key) {
var j = $scope.parsedJobs.filter(function(element) {
return element.category == value.category;
});
if (j.length > 0) {
$scope.parsedJobs[0].elements.push({
title: value.title,
location: value.location
});
} else {
$scope.parsedJobs.push({
category: value.category,
elements: [{
title: value.title,
location: value.location
}]
});
}
});
Fiddle

multiselect treeview in backbone

I'm new to backbone and trying to establish some good paradigms.
Right now, I'm working on a search heavy site. There are dozens of attributes to search on, many are min max type, but 6 or so are multi select. Prior to backbone, I was using something called listtree to make a collapsible listtree for the multiselect options. I'm still going to use those css classes, but now I'm trying to use backbone with models and views. TBH, this seems like more work than just using straight jquery, so maybe I'm missing something.
My question is, how should I structure the models and the views for several multiselect widgets in a treeview?
Here is the code I have so far:
<script type='text/template' id='listtree_bs'>
<div class="listtree">
<ul>
<% _.each(context, function(element, index){ %>
<li>
<span>
<input class="checkbox-listview-master" type="checkbox" value="<%= element.value %>"><%= element.name %><i class="glyphicon glyphicon-chevron-up"></i>
</span>
<ul style="display: none;">
<% _.each(element.items, function(childelement, index){ %>
<li>
<span>
<input class="checkbox-listview-master" type="checkbox" value="<%= childelement.value %>"><%= childelement.name %><i class="glyphicon glyphicon-chevron-up"></i>
</span>
</li>
<% }); %>
</ul>
</li>
<% }); %>
</ul>
</div>
</script>
var ListTreeModel = Backbone.Model.extend({
urlRoot: "/search/multiselect/",
idAttribute:'value',
});
var ListTreeModels = Backbone.Collection.extend({
model: ListTreeModel,
url: "/search/multiselect/",
parse: function (response) {
return response.data;
}
});
var listtreemodels = new ListTreeModels();
listtreemodels.fetch()
var ListTreeView = Backbone.View.extend({
events: {
"treechecked": "treechecked"
},
treechecked: function( e ){
console.log('triggered');
});
var listtreeview = new ListTreeView({el: $('#listtree_bs')});
The response.data from above looks kind of like this (I can easily change the backend though to facilitate the front end)
{
"data": [
{
"other": 0,
"values": [
{
"value": 1,
"key": "type (35513)"
}
],
"value": "type_of_code",
"key": "C Type",
"missing": 275793
},
{
"other": 25273,
"values": [
{
"value": 41,
"key": "United States of America (187293)"
}
],
"value": "primary_country_id",
"key": "Primary Country",
"missing": 3475
},
{
"other": 10958,
"values": [
{
"value": 623,
"key": "company 623 (12602)"
}
],
"value": "controller_id",
"key": "Search by Controller",
"missing": 248288
},
{
"other": 1294,
"values": [
{
"value": 6,
"key": "animal type (247267)"
},
{
"value": 7,
"key": "animal type y (23315)"
}
],
"value": "animal_id",
"key": "Animals",
"missing": 0
},
{
"other": 0,
"values": [
{
"value": 5,
"key": "Inactive (63693)"
},
{
"value": 1,
"key": "Active (825)"
}
],
"value": "current_status_code_table_id",
"key": "Current Status",
"missing": 109101
},
{
"other": 0,
"values": [
{
"value": 0,
"key": "stuff (275058)"
},
{
"value": 1,
"key": "more stuff (39860)"
},
{
"value": 2,
"key": "even more stuff (668)"
}
],
"value": "stuff_indicator",
"key": "Stuff Indicator",
"missing": 0
}
]
}
so right now, models are populated at the data level, but should they be populated at the nested level and manage this with some kind of one to many relationship?
What these multiselects do is fill out a search form that will get sent back to the server when the user hits search. Can I bind the above views to the model even if they are nested?
I'm trying backbone as an experiment here, but is this what it was really designed for? The search results are complicated and are sliced down in dozens of views. I was hoping to use backbone to keep the dom light and nimble. Right now it's getting bogged down in a lot of event call backs and just a lot of html.
Setting up a hierarchy of models is not that difficult : you just have to build your submodels when you parse the data. One way to do it is
var ListTreeModel = Backbone.Model.extend({
urlRoot: "/search/multiselect/",
idAttribute:'value',
constructor: function(data, opts) {
// force the parsing of the data
opts = _.extend({}, opts, {parse: true});
// setup the children collection
this.values = new ListTreeModels();
// call the parent constructor
Backbone.Model.call(this, data, opts);
},
parse: function(data) {
// populate the children
if (_.isArray(data.values))
this.values.set(data.values);
// remove the children from th emodel attributes
return _.omit(data, 'values');
}
});
var ListTreeModels = Backbone.Collection.extend({
model: ListTreeModel,
url: "/search/multiselect/",
parse: function (response) {
return response.data;
}
});
A demo showing the result http://jsfiddle.net/nikoshr/pZU5J/
Once your model structure is up and running, you can render your views (generate the associated HTML) and defined events. Here is a sample way to do it:
var ListTreeView = Backbone.View.extend({
'tagName': 'ul',
render: function () {
var $el = this.$el;
//create a view for each model
this.collection.each(function(model) {
var view = new ListItemView({
model: model
});
$el.append(view.render().el);
});
return this;
}
});
var ListItemView = Backbone.View.extend({
'tagName': 'li',
events: {
'click ': function(e) {
e.stopPropagation(); // avoid triggering an event on the parent level
console.log(this.model.get('value'));
}
},
render: function () {
//render the node
var template = _.template($('#listitem').html());
this.$el.html(template(this.model.toJSON()));
//and add a view for the sub collection
var subview = new ListTreeView({
collection: this.model.values
});
this.$el.append(subview.render().el);
return this;
}
});
with the listitem template defined as
<script type='text/template' id='listitem'>
<span>
<input class="checkbox-listview" type="checkbox" value="<%= value %>"> <%= key %>
</span>
</script>
And a demo http://jsfiddle.net/nikoshr/pZU5J/3/
Hierarchical views can be tricky to render, you probably will have to investigate further on the matter.

Resources