Building a auto-refreshing, nested List in EmberJS - javascript

how can i achieve to dynamically generate and update a nested list in EmberJS?
My Model looks something like:
App.Node = Em.Object.extend({
id: 0,
parentId: 0,
title: ""
});
The parentId represents the id of the direct parent element.
If i have data (instances of the model lying in the content of the controller) like:
[{
id:1,
title:"Parent Element"
}, {
id:2,
parentId:1,
title:"Child Element"
}]
I want to get a list like:
<ul>
<li>Parent Element</li>
<ul>
<li>Child Element</li>
</ul>
</ul>
This is what i got: http://jsfiddle.net/LhTCm/ (not runnable, but its easy to understand).
As i mentioned before, i want to build a nested list, which ui updates automatically as soon as the model-data changes.
Hope you can help!

Well the first thing you'll need is a better object model. Storing the parentID on your object doesn't help a lot. You need actual references to your objects, best in both directions, if you just want to display it, just storing the children will be fine as well. Your model should look like this:
App.Node = Em.Object.extend({
id: null,
parent: null,
title: "",
children: []
});
Then when you load in your data, you'll have to make sure that you map them correctly.
Your actual template would look like this
<ul>
{{#each node}}
<li>{{title}}
{{#each children}}
<ul><li>{{title}}</li></ul>
{{/each}}
</li>
{{/each}}
</ul>
You also might want to look at ember-data if your model is getting more complex (https://github.com/emberjs/data)

Related

Angular.js ng-repeat array shows as json

I have an issue where I'm trying to display an array in Angularjs using ng-repeat but its showing the entire json array and not only the text inside.
This is my array
$scope.problems = [
{
problem: "problem1",
works: [
"a0",
"a9"
]
}
]
And this is where I want to display it
<li ng-repeat="works in problems | filter: searchCard">{{works}}</li>
Now the {{works}} tag shows this in the live document:
{"problem":"probleem1","works":["a0","a9"]}
According to most tutorials and things i've seen its supposed to display the a0 and a9 not the entire json line.
My second question which might be completely different is, how can I display the text correctly but also hide all of them until a person has used the input to search the "works" input field.
when you have objects Array on ng-repeat you have to select that object params; in this sample our object params are "problem" and "works"
also in our object we have "string array" and string array not have params because that we use it directly in this sample {{work}} is object of string array.
<li ng-repeat="item in problems | filter: {problem: searchCard}">
{{item.problem}}
<ul>
<li ng-repeat="work in item.works">{{work}}</li>
</ul>
</li>
you can use the nested ng-repeats like #Maher mentioned. also, in order to hide data until searchCard is typed, you can use ng-if directive in nested ui.
<li ng-repeat="item in problems | filter: searchCard">
{{item.problem}}
<ul ng-if="searchCard">
<li ng-repeat="work in item.works">{{work}}</li>
</ul>
</li>

Working with ux-datagrid, angularJS and nested interations

I got it working excellent with one template but ran into an issue trying to replace my inner ng-repeat with another template. Kind of like grouped data or more like nested data.
so let me simplify my html here:
<div data-ng-controller="index.dataGridController" data-ux-datagrid="index.items" class="listA datagrid" data-addons="whichTemplate" grouped="'focus'">
<script type="template/html" data-template-name="default" data-template-item="item">
<div>
<h3>{{ item.obj.name }}</h3>
<!--- instead of
<ul>
<li ng-repeat="listItem in item.focus>{{listitem}}</li>
</uL
-->
</div>
</script>
<script type="template/html" data-template-name="innerFocus" data-template-item="item">
<div>
<ul>
<li>{{item.focus.id}}</li>
</ul>
</div>
</script>
</div>
and the index.items look like this:
[{
"obj": {
"name": "someName"
}
"focus": [
{"id": "something here"},
{"id": "Another etc"}
]
}]
// which template is basically copy and pasted from examples
angular.module('ux').factory('whichTemplate', function () {
return function (inst) {
// now we override it with our method so we decide what template gets displayed for each row.
inst.templateModel.getTemplate = function (item) {
var name = item.focus ? 'innerFocus' : 'default';
// now we get the template from the name.
return inst.templateModel.getTemplateByName(name);
};
};
});
Trying to iterate a list with the focus array. Any ideas? I think it would make for a great example in the docs. Adding a fiddle. http://jsfiddle.net/uftsG/88/
Instead of putting all focus array in one li i'm trying to get them spread out while also having the item.obj.name above the list.
I am not familiar with ux-data grid. If you are set on using it, you can ignore this answer, but I did a small search engine (purely for academic reasons) and i ended up using ng-grid to display the data. I followed the github documentation and ended up boot-strapping #scope.myDefs with the data I needed on the backend using a $scope.getMyData function. In the view all you really need to do is add input fields to get the data, and then a div class with your ng-grid. It's super cool because it ensures the code is modular, and there are no funky functions going on in the view with nested ng-repeats so on and so forth. The only part that gave me trouble was the CSS because I'm not bootstrap savvy yet :) Here's some docs if you end up interested in ng-grid at all.
http://angular-ui.github.io/ng-grid/

How to access 'foreign' fields in ng-repeat

I have two angularjs models and I would like to use firstkey of firstcollection as index value in the anothercollention. Basically I want to iterate over anothercollention.firstkey using the key from the previous ng-repeat. Here is some code which I hope makes sense of what I'm trying to do. I've checked all the angularjs docs but none seems to provide an example for this scenario. All of them assume that you have the data in the same ng-repeat model.
<ul>
<li ng-repeat="(firstkey, value) in firstcollection"></li>
<ul>
<li ng-repeat="(subkey, subvalue) in anothercollention.firstkey"></li>
<ul>
</ul>
Example
first collection {"fruits": "are the best", "veggies": "are the worst"}
another collection {"fruits": [1, 2, 3 ], "veggies":[2,4,5]},
HTML page should look like this:
fruits are the best
1, 2, 3
veggies are the worst
2,4,5
Ok, I guess I got it. All you need to do is:
<ul>
<li ng-repeat="(firstkey, value) in firstcollection"></li>
<ul>
<li ng-repeat="(subkey, subvalue) in anothercollention[firstkey]"></li>
</ul>
</ul>

How to bind-attr class active in EmberJS based on an array and a value?

I have a mode array and wants to set the active li based on the active property.
mode: ['list', 'grid', 'table'], // dynamic values
active: 'list',
For output:
<ul>
{{#each mode}}
<li {{bind-attr class="?:active"}}>
{{this}}
</li>
{{/each}}
</ul>
What will I put on the bind-attr part so that if the active property is set on any one of the mode array, it will bind an active class on the li?
Please help.
Create a child controller and add a computed property to indicate is active or not:
The ul controller(Use ApplicationController here for simplicity):
App.ApplicationController = Ember.ObjectController.extend({
mode: ['list', 'grid', 'table'],
active: 'list'
});
The li controller:
App.LiController = Ember.ObjectController.extend({
needs: ['application'],
isActive: function() {
return this.get('controllers.application.active') === this.get('model');
}.property()
});
The template:
<ul>
{{#each mode itemController="li"}}
<li {{bind-attr class="isActive:active"}}>
{{model}}
</li>
{{/each}}
</ul>
JSBin
Why do i need another controller?
From ember's doc, it says:
In Ember.js, controllers allow you to decorate your models with display logic. In general, your models will have properties that are saved to the server, while controllers will have properties that your app does not need to save to the server.
So, the extra controller's only purpose is to hold the isActive property.
What is {{content}} for?
content represents the controller's underlying object, in this case a string literal. It's not a reserved keyword, it's controller's property.
I updated my answer to use model instead of content, actually they are the same thing, you should always use the model property. See this question

Nested views in Ember.js

I have a container view which, among other things, displays a list of objects, like so:
{{#each}}
<div {{bind-attr class="author.first_name task"}}></div>
{{/each}}
I would like to hook a Javascript function everytime a DOM element is added to this list. I've tried doing:
didInsertElement: function() { ... }
But this hook apparently runs only the first time the view is initialized. I figured that maybe the hook doesn't run because the view is actually inserted once, and what's inserted more than once are just the nested element.
So should I use a nested view?
I tried something along these lines:
{{#each}}
{{#view App.SingleItemView}}
<div {{bind-attr class="author.first_name task"}}></div>
{{/view}}
{{/each}}
But in this case, though it works somehow, it doesn't get passed the necessary data that would render the properties such as author.first_name.
render will give you a new scope and is really easy to assign the content as well
<ul>
{{#each item in controller}}
{{render 'ind' item}}
{{/each}}
</ul>
http://emberjs.jsbin.com/alAKubo/1/edit

Categories

Resources