AngularJS select image from list - angularjs

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}];

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.

Ionic collection-repeat with ion-radio

I'm having a problem with setting checked on selected value using Icon collection-repeat with ion-radio.
Using the collection-repeat, if the selected item is the first item in the list, setting checked wouldn't work. To make it works I found, I need to make a delay assigning list data.
(If using ng-repeat, it works. But the list could be long, so I need to use the collection-repeat)
Example,
Template)
<ion-content class="has-header" ng-controller="Ctrl">
<div class="list">
<ion-radio
collection-repeat="item in list"
ng-model="selectedItem"
ng-value="item.id">
{{ item.n }}
</ion-radio>
</div>
</ion-content>
Controller)
angular.module('starter', ['ionic'])
.run(function($ionicPlatform) {
})
.controller('Ctrl',function($scope, $timeout) {
$scope.selectedItem = 1; // the first item
var list = [];
for (index = 1; index < 3; ++index) {
list.push({id: index, n: 'Item n. ' + index});
}
$scope.list = list;
});
The first item of the list wouldn't be checked. To make it works,
replace
$scope.list = list;
with
$timeout(function() {
$scope.list = list;
}, 500);
I want to know why it happened, and I don't think the 500ms is guaranteed, so I need to know right way to solve this. Please advice me.
It makes complete sense that you want to use collection-repeat over ng-repeat since the list could potentially be very long, and would be unnecessary to render all the items in the DOM at once using ng-repeat. Unfortunately this is a known bug within Ionic from what I have read and the work around to this is quite hacky. For instance the code below works with making active the 2nd radio:
Controller
.controller('Ctrl',function($scope, $timeout) {
$scope.data = {
selectedItem: 2
};
var list = [];
for (index = 1; index < 3; ++index) {
list.push({id: index, n: 'Item n. ' + index});
}
$scope.list = list;
});
HTML
<ion-content class="has-header" ng-controller="Ctrl">
<div class="list">
<ion-radio collection-repeat="item in list" ng-model="data.selectedItem" ng-value="item.id">
{{ item.n }}
</ion-radio>
</div>
</ion-content>
But when you change the selected item to 1, it does not show. Below is a workaround for what you are looking for. Start your loop at 0 and then hide that item using CSS (like I said "hacky"), give it a try.
Controller
.controller('Ctrl',function($scope, $timeout) {
$scope.data = {
selectedItem: 1
};
var list = [];
for (index = 0; index < 5; ++index) {
list.push({id: index, n: 'Item n. ' + index});
}
$scope.list = list;
});
HTML
<ion-content class="has-header" ng-controller="Ctrl">
<div class="list">
<ion-radio
collection-repeat="item in list" ng-model="data.selectedItem" ng-value="item.id" item-height="54" item-width="100.5%">
{{ item.n }}
</ion-radio>
CSS
.item-radio:first-of-type {
display: none;
}
.item-radio {
margin-top: -54px !important;
}
Hope this helps.

ng-repeat not working with set data structure

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;
};

Isolating re-used controller scopes with AngularJS

I'm currently working on a project where I use a primary navigation to open tabs which lazy-load templates.
EDIT: to clarify, the number of tabs can vary on a user basis, so I cannot do this hard coded.
My way to try and accomplish this is by using a Tabs-controller with headers and the tab-items themselves:
<section class="tabs" ng-controller="Tabs">
<div class="tabs__header">
<div class="tabs__header__item is-hidden" ng-repeat="tab in tabs" data-item="{{tab.item}}" ng-if="!tab.header">
<a class="tabs__header__item__text" ng-href="#/{{tab.item}}" ng-click="tabClicked($event)" data-item="{{tab.item}}">{{tab.name}}</a>
x
</div>
</div>
<div class="tabs__container">
<div class="tabs__container__tab is-hidden" ng-repeat="tab in tabs" id="tab-{{ tab.item }}" ng-if="!tab.header" ng-controller="Tab" ng-include src="template.url"></div>
</div>
</section>
And the controllers would look like this:
Tabs.js:
function Tabs(scope, root) {
root.$on('/general/page/initdata', function(e, data) {
//set default elements
scope.tabs = data['nav-primary'];
//open dashboard
});
root.$on('/nav/primary/open', function(e, itemName) {
root.$emit('/tabs/activate', itemName);
_setActiveTab(itemName);
});
scope.tabClicked = function(e) {
e.preventDefault();
var name = e.target.getAttribute('data-item');
_setActiveTab(name);
};
function _setActiveTab(itemName) {
var collection = document.querySelectorAll('.tabs__header__item.js-is-active, .tabs__container__tab.js-is-active');
angular.element(collection).removeClass('js-is-active');
collection = document.querySelectorAll('#tab-'+itemName+', .tabs__header__item[data-item="'+itemName+'"]');
angular.element(collection).addClass('js-is-active').removeClass('is-hidden');
}
};
Tabs.$inject = ['$scope', '$rootScope'];
Tab.js
function Tab(scope, root) {
var loaded = false;
root.$on('/tabs/activate', function(e, itemName){
if(scope.tab.item === itemName && !loaded) {
loaded = true;
scope.template = {url: '/frontend/templates/'+itemName+'.html'};
}
});
};
Tab.$inject = ['$scope', '$rootScope'];
Now, the problem is that template.url is modified for each tab whereas I only want to modify it for one tab. It turns out scope is shared between the various Tab-instances. How can I circumvent this?
It turns out the problem wasn't with AngularJS. I had simply made an error with my js-is-active class, causing the wrong tab to be displayed.

Tracking current selected item with AngularJS

I'm new to AngularJS and can't find any suitable answer for this. My app currently consists of a list of items displayed via Angular. There is also a label which displays the name of the currently selected item, and an input box which allows the name of the currently selected item to be modified.
What I cannot figure out is how to simultaneously:
Allow the selection of an item, which triggers the update of the label and the input box text to display the name of the newly selected item
Allow editing of the name in the input box which triggers the update of the label displaying the currently displayed item name
Edits to the name should be reflected in the original model item
At the moment, i'm trying to keep track of which item is current via a flag against the item and this isn't doing what I want. Ideally I would replace currentItem in the below with a direct reference to the item in items with isCurrent=true.
Current item name label:
`<div id="CurrentItem" data-ng-model="currentItem">{{currentItem.name}}</div>`
Current item name input box:
`<input id="ItemName" type="text" data-ng-model="currentItem" value="{{currentItem.name}}" />`
Display all items:
<div data-ng-repeat="item in items" data-ng-click="changeItem(item)">`
<img src="images/ItemIcon.png">
<div>{{item.name}}</div>
Controller:
var CoreAppController = function($scope, $location) {
$scope.changeItem = function(item) {
var length = $scope.items.length;
while(length-- ) {
$scope.items[length].isCurrent = false;
}
$scope.currentItem = item;
$scope.items.indexOf(item).isCurrent = false;
}
$scope.createItem = function(name, layout) {
$scope.items.push({ id: $scope.items.length + 1,
name: name,
isCurrent: false
});
}
// Initialisation
$scope.items = [];
$scope.createItem("Item 1");
$scope.createItem("Item 2");
$scope.items[0].isCurrent = true;
$scope.currentItem = $scope.items[0];
}
Any advice appreciated!
I'm not sure about your current code, but here is a mock up that does what it appears you're requesting.
The JS
app.controller('MainCtrl', function($scope) {
$scope.items = [
{ name: 'foo' },
{ name: 'bar' },
{ name: 'test' }
];
$scope.editing = null;
$scope.editItem = function(item) {
$scope.editing = item;
}
});
and the markup
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
{{item.name}}
<a ng-click="editItem(item);">edit</a>
</li>
</ul>
<div ng-show="editing">
<input type="text" ng-model="editing.name"/>
<span>{{editing.name}}</span>
</div>
</body>
Hopefully that helps. If you need more of a description, let me know.

Resources