ng-repeat not working with set data structure - angularjs

I'm trying to use ng-repeat with a field that is a Set in javascript https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Set. I tried use values(), keys(), entries() method from Set with ng-repat but is not working, anybody know a way, hack for this work?
Resumed code:
function Campaign () {
this.site = {
type : '',
domains : new Set()
};
}
controller:
.controller('CampaignStep1Ctrl', ['$scope', 'languages', 'geoLocationService',
function ($scope, languages, geoLocationService) {
var vm = this;
vm.campaign = $scope.campaign;
}
html:
<tr class="ui-widget-content ui-datatable-empty-message" ng-repeat="domain in vm.campaign.site.domains">
<td colspan="2">{{domain}}</td>
</tr>
Note: If i use console.log() and print domains attribute, it prints, i think that problem only is with ng-repeat.

An ES6 option -
return [...domains];

I used this solution
var devSet = new Set();
devSet.add(""One);
devSet.add(""Two);
...
$scope.deviceTypes = Arrays.from(devSet);
And in html
<ul>
<li ng-repeat="type in deviceTypes">
<p>{{type}}</p>
</li>
</ul>

This is probably not the best solution but you can make it work like this:
View:
<p ng-repeat="value in getSetAsArr(set)">{{ value }}</p>
Controller:
$scope.getSetAsArr = function (set) {
var arr = [];
set.forEach(function (value) {
arr.push(value);
});
return arr;
};

Related

How to call a function from another function, with ng-click?

var vm = this;
vm.dt_data = [];
vm.item = {};
vm.edit = edit;
vm.dtOptions = DTOptionsBuilder.newOptions()
.withOption('initComplete', function() {
$timeout(function() {
$compile($('.dt-uikit .md-input'))($scope);
})
})
.withPaginationType('full_numbers')
.withOption('createdRow', function (row, data, dataIndex) {
$compile(angular.element(row).contents())($scope);
})
.withOption('ajax', {
dataSrc: function(json) {
json['draw']=1
json['recordsFiltered'] = json.records.length
json['recordsTotal'] =json.records.length
console.log(json)
return json.records;
},
url: 'http://localhost:808/sistemadrp/public/ws/usuarios',
type: 'GET',
})
//.withDataProp('records')
.withOption('processing', true)
.withOption('serverSide', true);
vm.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('Id'),
DTColumnBuilder.newColumn('usuario').withTitle('Usuario'),
DTColumnBuilder.newColumn('nombre').withTitle('Nombre'),
DTColumnBuilder.newColumn('email').withTitle('Email'),
DTColumnBuilder.newColumn('telefono').withTitle('Telefono'),
DTColumnBuilder.newColumn('estado').withTitle('Estado'),
DTColumnBuilder.newColumn('created_at').withTitle('Creado'),
DTColumnBuilder.newColumn(null).withTitle('Acciones').notSortable().renderWith(function(data,type,full){
vm.item[data.id] = data;
return ' <a href="#" data-uk-modal="{target:\'#modal_header_footer\'}" ng-click="showCase.edit(showCase.item[' + data.id + '])">'+
' <i class="md-icon material-icons md-bg-light-blue-900 uk-text-contrast"></i></a>'+
' <a href="#" data-uk-modal="{target:\'#modal_header_footer_eliminar\'}" ng-click="showCase.edit(showCase.item[' + data.id + '])">'+
' <i class="md-icon material-icons md-bg-red-900 uk-text-contrast"></i></a>';
})
];
Table:
<div class="md-card-content" ng-controller="dt_default as showCase">
<table datatable="" dt-options="showCase.dtOptions" dt-columns="showCase.dtColumns" class="uk-table" cellspacing="0" width="100%">
</table></div>
With the answer I was given here to make use of $ compile already works this way
.withOption('createdRow', function (row, data, dataIndex) {
$compile(angular.element(row).contents())($scope);
})
Now when clicking the button I even call a modal and I command the object to make use of the ng-model
Thanks for the help, it works well.
EDIT: Added snippet for demonstrating the usage of $compile
In the html there is only a body tag for initialising the app and a div for initialising the controller.
In foo controller, two link are created as simple strings but with two ng-click respectively and then compiled with the $compile service. The result of that is then appended to the div which id is parent created as jQlite object (important aspect here!), so when the links are clicked the functions on their ng-click are executed (see console). It means AngularJS as interpreted properly the compiled html.
IMPORTANT: The difference between this and your code may be that your renderWith just take the parameter as a simple html node and not a jQuery/jQlite object. If that's the case you can not do what you're trying to do this way. You probably will need to find a workaround for this. For example: you could set a selector (i.e.: an id) for the result of the object returned by the DTColumnBuilder and then $compile that html node the same way I show in the snippet.
Original post
You should use the $compile service. Modify your function like this:
function actionsHtml(data, type, full, meta){
vm.usuario[data.id] = data;
var html = ' <i class="md-icon material-icons md-bg-light-blue-900 uk-text-contrast"></i>'+
' <i class="md-icon material-icons md-bg-red-900 uk-text-contrast"></i>';
return $compile(angular.element(html))($scope);
}
Snippet
angular.module('myapp', [])
.controller('foo', function($scope, $compile) {
var html = "<a class='hand' ng-click='hello()'><strong>Hi</strong> <small>(Click Me and take a look at console)</small></a>" +
"<br/> <hr/>" +
"<a class='hand' ng-click='goodby()'><strong>Goodby</strong> <small>(Click Me and take a look at console)</small></a>";
/*
* important!! if you don't use the angular.element syntaxt below, and instead you just use
* 'document.getElementById('parent') = $compile(html)($scope)', for instance, it will be shown something like '[object], [object]'
*/
angular.element(document.getElementById('parent')).append($compile(html)($scope));
$scope.hello = function() {
console.log("Hi there!")
}
$scope.goodby = function() {
console.log("Goodby!")
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<style type="text/css">
.hand {
cursor: hand;
cursor: pointer;
}
</style>
<body ng-app="myapp">
<div ng-controller="foo">
<div id="parent"></div>
</div>
</body>
It looks like a scope issue to me.
This means at run time, when the button is clicked, it cannot find the edit function.
If you add this line below vm.usario = {};
vm.edit = edit;
Then change your ng-click="showCase.edit( to be
ng-click="vm.edit( ...
Then the button should be able to find the function.

angularjs : Why does the filter not work?

Please help fix the script.
html:
<li ng-repeat="date in dateArr | dateFormatter}">
<span class="date">{{date}}</span>
</li>
js:
angular.module('App', [])
.controller('lsController', function ($scope) {
$scope.dateArr = [
'10.10.2016',
'11.10.2016',
'12.10.2016',
'13.10.2016',
'14.10.2016',
'15.10.2016'
];
/*$scope.dateFormatter = function(date) {
return date.slice(0, 6);
}*/
})
.filter('dateFormatter', function (date) {
return date.slice(0, 6);
});
I use angular 1.4.8
JSFIDDLE
I need use filter, which cut the datestring
Your filter is not constructed properly.
A filter needs to return a function that contains the arguments for the filtering and returns the result
.filter('dateFormatter', function () {
return function(dateString){
return dateString.slice(0, 6);
}
});
Then you have this set to filter in the ng-repeat but putting it there it would need to return a filtered array, not a string input and manipulation. So it needs to be placed where you pass in a string
<li ng-repeat="date in dateArr">
<span class="date">{{date | dateFormatter}}</span>
</li>
DEMO
Your filter is wrong. Check de filter documentation for more details
.filter('dateFormatter', function () {
return function(date){
return date.slice(0, 6)
}
});
Also the way you use your filter is wrong. Take it out of ng-repeat
<span class="date">{{date | dateFormatter }}</span>
FIDDLE

how to send id from one controller to another in angular

I have a basic controller that displays my Software Group name:
var SoftwareGroupApp = angular.module('SoftwareGroupApp', []);
SoftwareGroupApp.controller('SoftwareGroupController', function($scope, $http) {
$http.get("select_SoftwareGroup.php")
.then(function (response) {$scope.result = response.data.records;});
});
In my view I'm displaying this Software Group in a list
<ul class="sub-menu">
<div ng-app="SoftwareGroupApp" ng-controller="SoftwareGroupController">
<li ng-repeat="x in result"><a class="haschild" title="" href="">{{ x.GroupName }}</a>
<ul>
<div ng-controller="SoftwareController">
<li ng-repeat="x in names"><a title="" href="">{{ x.name }}</a></li>
</div>
</ul>
</li>
</div>
</ul>
and i have another controller that display my Software name :
var SoftwareApp = angular.module('SoftwareApp', []);
SoftwareApp.controller('SoftwareController', function($scope, $http) {
$http.get("selectSoftware.php")
.then(function (response) {$scope.names = response.data.records;});
});
when someone click on the Software Group name, i have another sub menu that list my software name .
<ul>
<div ng-controller="SoftwareController">
<li ng-repeat="x in names"><a title="" href="">{{ x.name }}</a></li>
</div>
</ul>
What I'm trying to do is when someone click on the Software Group name, my Software group id save in a variable and send to my SoftwareController . and i display names of software that == id
I would suggest you to use $rootScope.broadcast for this kind of operation. To be very short you can use broadcast like this.
I one controller where you want to send data write like this:
$rootScope.$broadcast("yourFuction", data);
In the receiver controller get this data like this:
$rootScope.$on("yourFuction", function(data){
//do something
});
check this for more information: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
Thanks.
Your best solution would be to use uirouter, rather than ng-controller, and pass the ID as a state parameter.
Another option would be to use components rather than ng-controller, which you can pass parameters to.
There are so many ways. I will mention you one way:
You can create a service to store Id which you want to send into another controller like below:
angular.module('app').factory('commonService', function () {
var myValue;
return {
set: function (o) {
this.myValue = o;
},
get: function () {
return this.myValue;
}
};
});
Now, inject this service into both controller like below:
angular.module('app').controller('firstController', function ($scope, commonService) {
$scope.setValue = function (value) {
commonService.set(value);
};
});
And,
angular.module('app').controller('SecondController', function ($scope, commonService) {
$scope.getValue = function () {
$scope.value = commonService.get();
};
});

Multiple ng-repeat on single element

Is this possible to achieve a code like this:-
<tr ng-repeat="data in dataArray,value in valueArray">
{{data}} {{value}}
</tr>
I am having two arrays I want to show them in single row.
PS: I am not asking for syntax. I am looking for logic to achieve this
Thanks
Like :- "http://jsfiddle.net/6ob5bkcx/1/"
You should be doing this in the controller, not in the view. Map the dataValues into a key/value pair object and reference the values array using an index. This assumes that each data key has a corresponding value key.
Controller:
var dataArray = [];
var valueArray = [];
this.repeatData = dataArray.map(function(value, index) {
return {
data: value,
value: valueArray[index]
}
});
View:
<tr ng-repeat="data in repeatData">
{{data.data}} {{data.value}}
</tr>
Does this suits your need
http://jsfiddle.net/jmo65wyn/
Your data, value array as object array
this.obj = [{data: 'a', value :true}, {data: 'b', value:true}];
And you loop like this
<div ng:repeat="o in obj">
{{o.data}} and {{o.value}}
<input type="checkbox" ng:model="o.value">
</div>
Angular ng-repeat does not support it but still you can write your own custom directive according to your requirements.
Update Section
var traverseCollection = angular.module("CollectionTraverse", []);
traverseCollection.directive("repeatCollection", function(){
return {
restrict: "A",
scope: {
model: "="
},
controller: controller: function($scope) {
var collectionList = $scope.model;
angular.forEach(collectionList, function(obj, index) {
angular.forEach(obj, function(data, index) {
});
});
}
}
});
Your scope should contains the list of your collection objects : $scope.collectionList = [dataArray, valueArray];
Usage in HTML:
-------------------------------------------
<div repeat_collection model="collectionList"></div>
This directive will be generic to traverse list of collections and yes in the above code there can be some syntactical errors because i did not run it. Its your luck.
If you have, for any reason, two arrays with the same length and where their contents are corresponding (array1[0] correspond to array2[0], ..., array1[n] correspond to array2[n]), you can use AngularJS's track by (which was introduced for the 1st time in the version 1.1.4) like this for example :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular.min.js"></script>
<table ng-app="" ng-init="names=['Bill','Billa','Billy']; ages=['10', '20', '30']">
<tr ng-repeat="name in names track by $index">
<td>{{ name }} is {{ ages[$index] }} years old.</td>
</tr>
</table>
Hope that can help.
if you want something like a list with two or more items in the same row:
in html file:
<li ng-repeat="item in items">
<i class="material-icons">{{navItem[1]}}</i>{{navItem[0]}}</li>
in js file:
$scope.items = [
["Home", "home"],
["Favorite", "favorite"]
]

AngularJS select image from list

I'm implementing simple pictures list.
here's my code. I have 2 questions:
1. I want to make a single choice whenever the user click an image. Whenever he choose one picture it will clear the other choice. how can I do that?
2. Instead of border I would like to use an icon such as fa-check (http://fontawesome.io/icon/check/). How can I combine it in the css?
Thanks!
css file
.selected {
border:2px solid red;
}
js file
$scope.items = [
{imageUrl: '/app/img/item1.jpg'},
{imageUrl: '/app/img/item2.jpg'}];
$scope.toggle = function (item) {
item.selected = !item.selected;
};
html file
<div class="category rating-type">
<h5>items list</h5>
<div class="pics-continer">
<ul>
<li ng-repeat="item in items" ng-click="toggle(item)" ng-class="{'selected':item.selected}">
<div style="background-image: url({{item.imageUrl}});height:36px; width:40px;display:inline-block"></div>
</li>
</ul>
</div>
Change your taggle method as follows to have a single select image list.
$scope.toggle = function (item) {
$scope.selectedImage = item.imageUrl;
};
And change the view as
<li ng-repeat="item in items" ng-click="toggle(item)" ng-class="{'selected':item.imageUrl == selectedImage}">
<img src="{{item.imageUrl}}" style="height:36px; width:40px;"/>
</li>
So only one image can be selected at the same time.
For using an icon instead of border you can set the icon as background image.
the following link are usefull
CSS background-position Property
I think it is best put as much code as possible in the controller - this is easier to test. So: the html snippet:
<li ng-repeat="item in items" ng-click="selectItem(item)"
ng-class="{'fa fa-check':isSelected(item)}">
<div style="background-image: url({{item.imageUrl}});
height:36px; width:40px;display:inline-block"></div>
</li>
the controller:
controller('TestController', function($scope){
$scope.items = [
{imageUrl: '/app/img/item1.jpg'},
{imageUrl: '/app/img/item2.jpg'}
];
$scope.selectedItem = null;
$scope.selectItem = function(item){
$scope.selectedItem = item;
};
$scope.isSelected = function(item){
if($scope.selectedItem===null){
return false;
}
return item.imageUrl === $scope.selectedItem.imageUrl;
};
})
how to setup fontawesome is documented here: http://fontawesome.io/get-started/ After that you can use the css class names provided by fontawesome. Also included in the example above.
$scope.items = [
{imageUrl: '/app/img/item1.jpg'},
{imageUrl: '/app/img/item2.jpg'}];
$scope.toggle = function (item) {
item.selected = !item.selected;
};
that item is a index for items, but you didn't set selected in your items array . So item.selected it's threw undefined error
Please try this way
$scope.items = [
{imageUrl: '/app/img/item1.jpg',selected:true},
{imageUrl: '/app/img/item2.jpg',selected:false}];

Resources