angular handsontable not working with regular scope variable - angularjs

I have and angular scope variable called xd which i am trying to display in a table. When i use a regular table, it works fine:
<table class="table">
<tr ng-repeat="x in xd">
<th ng-bind="x.title"/>
</tr>
</table>
Now i am trying to use ngHandsonTable for the same purpose. As the documentation is still not proper, i tried something like this but somehow it is not showing anything. How do i use it to function properly?
<hot-table id="previewTable" columnHeaders="false" settings="htSettings" datarows="xd" >
</hot-table>
sample dataset of xd:
[
{
"title": "mytitle1"
}
{
"title": "mytitle2"
}
{
"title": "mytitle3"
}
]
Another output of xd:
[
{
"primary": "2",
"title": "mytitle1"
}
{
"primary": "3",
"title": "mytitle2"
}
{
"primary": "4",
"title": "mytitle3"
}
]
I would like to dynamically assign these column headers and values in the <hot-table>

After fiddling around with this, I came up with:
HTML table:
<div ng-app="demoApp" ng-controller="demoCtrl">
<hot-table
id="demoTable"
datarows="xd"
settings="{
colHeaders: xdColumns
}">
</hot-table>
</div>
Where the columns are the attribute names:
$scope.xdColumns = Object.keys($scope.xd[0]);
See this fiddle: https://jsfiddle.net/hysx1g10/4/
Since your data looks kind of confusing (every item has a title attribute), I'm not sure if that's what you're looking for. But as in a regular table you got one member (of the xd array) per row.

Related

Accessing an array property on every object in an array, with ng-repeat

I've spent ages trying to solve this, and I can't...
I have an array: clubData.
In that array is a series of objects, which represent individual football clubs.
In each club object, is an array assigned to the property squad.
Here's a sample of clubData:
[{
"league": "0",
"id": "0",
"name": "AFC Bournemouth",
"codeName": "afc-bournemouth",
"nickName": "Cherries",
"dateFounded": "1899",
"stadium": "Dean Court",
"manager": "Eddie Howe",
"squad":
[
{"clubCode": "afc-bournemouth",
"firstName": "Artur",
"lastName": "Boruc",
"nationality": "pl",
"country": "Poland",
"position": "gk",
"shirtNumber": "1",
"age": "36"},
{"clubCode": "afc-bournemouth",
"firstName": "Glenn",
"lastName": "Murray",
"nationality": "gb-eng",
"country": "England",
"position": "fw",
"shirtNumber": "27",
"age": "32"}
]
}, {
"league": "0",
"id": "1",
"name": "Arsenal",
"codeName": "arsenal",
"nickName": "Gunners",
"dateFounded": "1886",
"stadium": "Emirates Stadium",
"manager": "Arsène Wenger",
"squad": [ etc... ]
}
]
I want to run an ng-repeat on an md-card (Angular Material directive), so every object (player) in every squad is repeated as a card.
My current method:
I used an outer and inner div with two separate ng-repeats. The issue with this is it necessarily repeats the outer div, which causes a 'break' at the end of every outer div repeat, when I just want the inner div repeated as individual units.
My HTML currently looks like this:
<span ng-repeat="item in clubData" layout="row" layout-wrap>
<md-card ng-repeat="player in item.squad" layout="row" layout-wrap>
<md-card-header>
<md-card-avatar>
<div class="clubavatar club-icon-{{player.clubCode}}"></div>
</md-card-avatar>
<md-card-header-text>
<span class="md-title">{{player.firstName + " " + player.lastName}}</span>
<span class="md-subhead"><span class="flag-icon flag-icon-{{player.nationality}} nationid md-whiteframe-1dp"></span>{{player.country}}</span>
</md-card-header-text>
</md-card-header>
</md-card>
</span>
My attempted (and failed) solution:
Ideally, I want to come up with an expression in ng-repeat that will iterate through the elements but only print the squad arrays.
I thought something like this might work (but it doesn't):
<md-card ng-repeat="player in clubData[$index].squad">{{player.name}}</md-card>
Logically (to me) that would print out...
<md-card ng-repeat="player in clubData[0].squad">{{player.name}}</md-card>
<md-card ng-repeat="player in clubData[1].squad">{{player.name}}</md-card>
<md-card ng-repeat="player in clubData[2].squad">{{player.name}}</md-card>
Perhaps I'm misusing $index?
If there's something I'm missing, or an alternative working solution, would really appreciate someone's help.
Thanks in advance.
Are you looking for something like this?
Inside your controller
$scope.players = clubData.reduce(function(a,c){
return a.concat(c.squad);
},[]);
Using forEach
$scope.players = [];
$scope.clubData.forEach(function(c) {
$scope.players = $scope.players.concat(c.squad);
});
and on view:
<md-card ng-repeat="player in players">{{player.name}}</md-card>
Response to your jsfiddle: https://jsfiddle.net/Lt7aP/2342/
Solution using forEach: https://jsfiddle.net/Lt7aP/2344/
Explanation - reduce
reduce is higher order function, very common with functional programming. it takes following form ...
es6 (or you can use babel for support):
//Will return final value of accumulator!
<array>.reduce(function(accumulator,current){
//accumulator: accumulated result for each iteration
//current: current item for given iteration
//accumulator is empty array or array of players
//we just concat current's squad array
var mergedPlayers = accumulator.concat(current.squad);
//This return will set accumulator to returned value
//for next iteration.
return mergedPlayers;
},
[] //Default accumulator empty array.
);
you can also use lodash, slight syntax change
_.reduce(<array>,function(accumulator,current){
/* your awesome code goes here*/
},[]);
Hope this helps!

How do I filter angular results by id and other keys?

I want to filter results by id, or rating and various other keys, I'm using this data structure:
[
{
"id": "1"
"Description": "desc 1",
"Rating": "rating 1",
"MainImage": "image.jpg"
},
{
"id":"1"
"Description": "desc 2",
"Rating": "rating 2",
"MainImage": "image.jpg"
},
{
"id": "2"
"Description": "desc 3",
"Rating": "rating 3",
"MainImage": "image.jpg"
}
]
This data is returned from a promise and is assigned to $scope.results. In the template there is an ng-repeat to iterate over the results. This is working fine, my question is:
How do I filter the results by id so for example only the results with the id of 1 are displayed? I had this working but it wasn't the most efficient. I reassigned the filtered results back to $scope.results which did work but then the entire data structure had been replaced by the one containing the filtered results. That obviously wasn't going to work and I did a work around but I know this isn't the best way.
I need a custom filter that will be able to handle filtering using 3 different select lists so for example a rating select list, a productId and a productName.
How exactly would I write this function?
<div class="product" data-ng-repeat="product in products | filter:searchFilter"></div>
I ended up doing something that I found here and created a function in the backend. Something like:
$scope.searchFilter = function (item) {
return (item.id === $scope.results.id)
}
This code isn't exactly what I've used but that's the general idea. Seems to work :)
//This will filter the product list based on all 3 criteria
<div class="product" data-ng-repeat="product in products | filter:{rating:selectedRating, id:selectedId,productName:selectedProduct }"></div>
This is how I do it.
<input type="number" ng-modal="idFilter:selectedID">
<div ng-repeat="result in results | idFilter:selectedID | track by $index">
<something-repeated>
</div>
<script>
angular.module('whatever').filter('idFilter', function(){
return function(results, selectedID){
return results.filter(function(result){
return result.id == selectedID;
});
}
});
</script>

AngularJS custom directive within ng-repeat with dynamic attributes and two way binding

I'm banging my head on the wall over this for days and finally decided to post this question since I can't find an answer that matches what I'm trying to do.
Context: I'm building a dynamic form building platform that describes form elements in a JSON structure like this -
{
"name": "email",
"type": "email",
"text": "Your Email",
"model": "user.profile.email"
}
And then in the View I have a recursive ng-repeat that includes the field template like this -
<script type="text/ng-template" id="field.html">
<div ng-if="field.type === 'email'" class="{{field.class}}">
<p translate="{{field.text}}"></p>
<input type="{{field.type}}" name="{{field.name}}" class="form-control" dyn-model="{{field.model}}">
</div>
</script>
As you see, I use a custom directive dynModel to create the ng-model attribute with interpolated value of the model from the string value. So far do good.
Now I have a more complex scenario in which I have a collection of fields that can be added or removed by clicking on Add button or removeMe button. See below -
{
"name": "urls",
"type": "collection",
"text": "Your Profile URLs",
"model": "user.profile.urls",
"items": [
{
"name": "url",
"type": "url",
"text": "Facebook URL",
"model": "url"
},
{
"name": "url",
"type": "url",
"text": "Facebook URL",
"model": "url"
}
],
"action_button": {
"name": "add",
"type": "action",
"action": "addURL"
}
}
<div ng-if="field.type === 'collection'">
<button class="btn btn-info" dyn-click click-action="{{field.action_button.action}}" click-model="{{field.model}}">{{field.action_button.text}}</button>
<div dyn-ng-repeat="item in {{field.model}}" >
<div ng-repeat="field in field.items" ng-include src="'field.html'"></div>
</div>
</div>
As you'll notice, I have another custom directive that takes care of interpolation of {{field.model}} from the previous ng-repeat (not shown).
Now to the crux of the issue. As you see in the template, I have nested ng-repeats, the first one iterates through user.profile.urls and the second one iterates through the field parameters in JSON and creates the HTML tags, etc. One of those fields is a button (action_button) that is used to add more URLS to the list. When I click the button, I want it to trigger a function in my controller and effectively add a new child to the parent model (user.profile.urls). I then also want each URL, existing and new to have a remove button next to them that will be dynamic and will remove that particular item from the model.
If you see the code above, I have a custom directive dyn-click that reads in the
click-action="{{field.action_button.action}}"
That contains the function name (addURL) to be called that resides in my controller and the model
click-model="{{field.model}}"
(user.profile.urls) to which the new item is to be added. This is not working. The reason for this complexity is that I have multiple levels of nesting and at each level there are dynamic elements that need to be interpolated and bound. The directive dyn-click looks like this right now -
exports = module.exports = function (ngModule) {
ngModule.directive("dynClick",function() {
return {
restrict: 'A',
link: function(scope,element,attrs) {
$(element).click(function(e, rowid){
scope.clickAction(scope.clickModel, scope.$index);
});
}
};
});
};
With this code, when I click on the rendered form's Add button, the code in the $(element).click method above gets executed giving the following error -
Uncaught TypeError: undefined is not a function
I have tried a few different things with scope:{} in the dyn-click directive, with different errors and none of them have worked completely with two way binding of the model and calling the function as expected.
Help!
EDIT-1 - please see the comments:
$(element).click(function(e, rowid){
scope.$eval(attrs["clickAction"])(scope.$eval(attrs["clickModel"]), scope.$index);
});
EDIT-2: The plunker is here - http://plnkr.co/edit/DoacjRnO61g4IYodPwWu?p=preview. Still tweaking it to get it right, but you guys should be able to see the necessary pieces. Thanks!
EDIT-3: Thanks Sebastian. The new plunker is here - http://plnkr.co/edit/Z6ViT7scubMxa17SFgtx?p=preview . The issue with the field.items ng-repeat still exists. For some reason the inner ng-repeat is not being executed. Any ideas? Josep, Sebastian?

Resolving object dependencies on client using Restangular

I have problems with restoring my entity relations at the (AngularJS) client after retrieving them via REST using Restangular. I searched a lot, but could not find a clean solution. I have some years of programming experience, but I'm quite new to the AngularJS ecosphere and the REST paradigm.
The task
At my Spring Data backend I have two entities, Article and ArticleGroup, in a 1:n relationship. The resulting REST json (via Spring Data Rest) looks like this:
Article
{
"_embedded": {
"articles": [
{
"id": 1,
"name": "A Drink",
"price": 2.90,
"created": null,
"modified": null,
"active": false,
"displayOrder": 0,
"_links": {
"self": {
"href": "http://localhost:8080/articles/1"
},
"articleGroup": {
"href": "http://localhost:8080/articles/1/articleGroup"
}
}
},
...
ArticleGroup
{
"_embedded": {
"articleGroups": [
{
"id": 1,
"name": "Drinks",
"printer": null,
"_links": {
"self": {
"href": "http://localhost:8080/articleGroups/1"
},
"articles": {
"href": "http://localhost:8080/articleGroups/1/articles"
}
}
},
...
Now I want to display a tabgroup containing the articleGroup.name as the tab's label and a table of the articles in this articleGroup as its content:
<tabset>
<tab ng-repeat="group in articleGroups" heading="{{group.name}}">
<table class="table">
<tr ng-repeat="article in group.articles">
<td ng-click="increase(article)">{{article.name}}</td>
<td>{{article.price | currency }}</td>
...
</tr>
</table>
</tab>
</tabset>
I retrieve the articleGroups easily in my AngularJS controller using Restangular:
Restangular.all('articleGroups').getList()
.then(function(groups) {
$scope.articleGroups = groups;
});
This works fine and the tabs show up nicely. Now I can do so for the articles as well, but here I come upon the problem which I'm dealing with for days now.
The problem
How can I filter the articles for their articleGroup so every portion of articles appears in the right tab? What is the right expression in the ng-repeat above where I just put "group.articles" as a placeholder now?
This sounds very easy, but my problem is that I have no operational identification of an Article's articleGroup to filter the right articles in the ng-repeat for each tab. What I tried:
using the self.href as an id à la article._links.articleGroup.href == articleGroup._links.self.href, but this doesn't work as you can see in the JSON above those two links are set up differently
adding (database) ids to the JSON, but of course an article does not contain the id of its articleGroup, but only the link relation
looping through articleGroups and retrieving each group's articles into an array with the articleGroup.id as the key, but I can't get this to work out as I either get undefined errors by JavaScript or infinite loops
Help
Before I continue fiddling along for hours, it would be great if you could give me hints on which direction to take and what a "clean" and methodologically sound approach to the task would be. How can I bring articles and their corresponding group back togehter?
It seems like such an easy (and frequent) problem, but I tried for hours and days to get it running and fear I'm missing something. I looked at many examples but none of them helped me to have a breakthrough.
I'm happy to provide any further information as needed. Thanks a lot in advance!
Well, I solved it. It turned out that I got lost in the handling of asynchronous requests, especially between having a data object itself and a promise for a request, i.e. placeholders which provide access to the data as soon as it is available - very well explained in this post.
Restangular always returns promises. So I came up with the following solution which works exactly as I wanted to:
For the controller code:
Restangular.all('articleGroups').getList()
.then(function(groups) {
$scope.articleGroups = groups;
for(i=0;i<groups.length;i++) {
$scope.articles[groups[i].id] = groups[i].getList("articles")
}
});
So when the articleGroups arrive from the server, I walk through all of them and put them into the array $scope.articles with the articleGroup.id as key. Notice that group[i].getList("articles") returns a promise for the articles relation. With Restangular's $object property, I receive the articles data array in the ng-repeat:
<tabset>
<tab ng-repeat="group in articleGroups" heading="{{group.name}}">
<table class="table">
<tr ng-repeat="article in articles[group.id].$object | orderBy:'id':false ">
<td>{{article.name}}</td>
<td>{{article.price | currency }}</td>
</tr>
</table>
</tab>
</tabset>
Now, all articles of the selected articleGroup's tab are displayed on the tab. While this seems fine, I'm still not sure if this is the best solution in terms of style or performance. But at least it's a step ahead. Comments very welcome.

Angular JS: Handling different UI components from each views repeated using ng-repeat when the view look-feel are same

Apologies for the big Title, I couldn't come up with any thing better. Let me explain the issue I am having.
I have to render three cards where each of them share same look-feel, means each of them have a header section and a body section. I am using ng-repeat to get data from model and render these cards.
Code:
<div class="card">
<h1>{{card.title}}</h1>
<div ng-repeat="widget in card.widgets" class="widget">
<h2>{{widget.title}}</h2>
{{widget.type}}
</div>
</div>
Now, each of these Card's body should have different UI in it. For example, One card's body might have a chart using Hight Charts, Another one might just want to use a UI from jQuery UI library, etc..
How would I achieve it when I am looping using ng-repeat? Let me know if my starting direction is correct?
The model data look like this:
[
{
"id": "c001",
"title": "CARD 1",
"widgets": [
{
"title": "title 1.1",
"type": "line-graph"
},
{
"title": "title 1.2",
"type": "bar-chart"
}
]
},
{
"id": "c002",
"title": "CARD 2",
"widgets": [
{
"title": "title 2.1",
"type": "graph"
},
{
"title": "title 2.2",
"type": "bar-chart"
}
]
},
{
"id": "c003",
"title": "CARD 3",
"widgets": [
{
"title": "title 3.1",
"type": "line-graph"
},
{
"title": "title 3.1",
"type": "bar-chart"
}
]
}
]
Looking for help on this.
Thank You.
The solution for your problem is to combine both ng-switch and ng-repeat to achieve the effect you are attempting to get. Basically you would repeat over the items and switch between its type. Angular only includes the part of the DOM which matches the switch.
Here is a rough idea / html of what you should be doing.
<div class="card">
<h1>{{card.title}}</h1>
<div ng-repeat="widget in card.widgets" class="widget">
<h2>{{widget.title}}</h2>
<div ng-switch on="widget.type">
<div ng-switch-when="line-graph">
<!--do something here relevant to line graph-->
<div line-graph="widget.data"></div>
</div>
<div ng-switch-when="graph">
<!--do something here relevant to graph-->
<div graph="widget.data"></div>
</div>
<!-- and so on... add more if you need-->
</div>
</div>
</div>
I'm newer to Angular, but I believe you could encapsulate all of it through a directive. The idea would be we would have our own directive that we add to a div and then pass in the type and from there the directive could handle the logic and create the appropriate chart/element/whatever and do all the creation in the javascript file for the directive.
<div chart="line-graph"></div>
<div chart="bar-chart"></div>
module.directive('chart', function(){
return{
//logic to build various charts with different libraries here
}
});
It might be a pretty complicated directive to write, but it would be an elegant way to write it. #ganaraj did have that above with div graph="widget.data" inside of the ng-switch, but didn't really mention the directive part, just the switching. That would make the individual directives simpler, so may be the better overall approach, if each type is going to be vastly different.
This post below from simpulton is really good covering the directives portion of it. You can even make it a step further and make it more like a widget where the tag could be (his "act five: widget directive") and then to that pass in the type and the data to go with it. He is writing a directive to do animantion on some cirlces created in CSS, so there's no reason you couldn't use it to apply some highchart or jQuery UI code. It's really well written and includes code in jsfiddle so you can see it work as well.
http://onehungrymind.com/angularjs-directives-basics/

Resources