Limit number of chips display - angularjs

I'd like to display only a the first three chips of a list, and put a marker that there are more to see (like three dots for example).
Is there a way to do so with the <md-chips> directive ?
I'd prefer specify that I'm talking about a read-only chips list, not editable. I've tried with md-max-chips but it only controls the add of new chips.
Some piece of code :
<div layout="row" layout-align="start center">
<md-chips ng-model="mylist" readonly="true"></md-chips>
</div>
How I would like it to be displayed (the header is not in the code)

Try this solution:
HTML:
<md-chips ng-model="ctrl.visible" readonly='true' ng-click="ctrl.select($event)">
</md-chips>
Javascript:
self.fruitNames = ['Apple', 'Banana', 'Orange', 'Test1', 'Test2', 'Test3', 'Test4'];
var i = 0;
function ModifyVisible(){
self.visible = self.fruitNames.slice(0, (3 * ++i));
if(self.fruitNames.length > self.visible.length)
self.visible.push('...');
}
ModifyVisible();
self.select = function($event) {
if($event.path[0].textContent == '...')
ModifyVisible();
}

You may going to try to manipulate your list object like in this codepen demo. The last item is an placeholder item. You should manipulate your list before rendering / binding to view.
self.vegObjs = [
{
'name' : 'Broccoli',
'type' : 'Brassica'
},
{
'name' : 'Cabbage',
'type' : 'Brassica'
},
{
'name' : 'Carrot',
'type' : 'Umbelliferous'
},
{
'name' : '...',
'type' : ''
}
];

Related

Comparing objects from two scopes to provide a value

I'll try to simplify the problem as much as I can.
Let's say I have 2 scopes
$scope.section1 = [
{label: 'label1'},
{label: 'label2'}
];
$scope.section2 = [
{value: 'one'},
{value: 'two}
];
Those scopes are used to generate buttons with ng-repeat
<button ng-repeat="item in section1 type="button">{{item.label}}</button>
and
<button ng-repeat="item in section2 type="button">{{item.value}}</button>
Now what I would like to do it to create a third scope that would attach values to the combinations of objects from the two previous ones, say:
$scope.combo = [
{ section1.label:label1 + section2.value: one = 'result1' },
{ section1.label:label2 + section2.value: one = 'result2' },
{ section1.label:label1 + section2.value: two = 'result3' },
{ section1.label:label2 + section2.value: two = 'result4' }
];
Now here comes the tricky part. What I would need to do, is to add a function that would take the values of clicked ng-repeat buttons from each section and then display the results based on the third scope in an input field or something.
So, if you click the button with label:label1 and the one with value:two the input field would show result3.
I'm very green when it comes to Angular and I have no idea how to approach it, especially that all values are strings.
If I understand correctly you could setup your combo something like ...
$scope.combo = {
"label1": {
"one": "result1",
"two": "result2"
},
"label2": {
"one": "result3",
"two": "result4"
}
}
You can then reference the correct value as combo[valueFromButton1][valueFromButton2] where valueFromButton1 and valueFromButton2 point at a model that contains the result of the clicked buttons. Your controller function then just needs to tie everything together by updating the model when the buttons are clicked.
See this plunkr ... https://embed.plnkr.co/GgorcM/
Without changing much you can also try like below provided code snippet.Run it to check the demo.
var app = angular.module('app', []);
app.controller('Ctrl',['$scope' ,function($scope) {
var key1, key2;
$scope.click = function(type, item) {
if (type == 'label') {
key1 = item;
} else if (type == 'val') {
key2 = item;
}
$scope.key = key1 + '+' + key2;
angular.forEach($scope.combo, function(val, key) {
if(val[$scope.key]){
$scope.finalVal = val[$scope.key];
}
});
};
$scope.section1 = [{
label: 'label1'
}, {
label: 'label2'
}];
$scope.section2 = [{
value: 'one'
}, {
value: 'two'
}];
$scope.combo = [{
'label1+one': 'result1'
}, {
'label2+one': 'result2'
}, {
'label1+two': 'result3'
}, {
'label2+two': 'result4'
}];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='Ctrl'>
<button ng-repeat="item in section1" ng-click="click('label',item.label)" type="button">{{item.label}}</button>
<button ng-repeat="item in section2" ng-click="click('val',item.value)"type="button">{{item.value}}</button>
<input type="text" ng-model="finalVal"/>{{key}} {{finalVal}}
</div>

AngularJS: function call with ng-class

i am calling a function from ng class because i want to return class name dynamically based on price.
i have 6 data and function suppose to call 6 times but when i run the code then i saw it is calling 12 times.....anyone can see the code and tell me why the function is getting called 12 time instead of 6.
<div ng-app="myApp">
<ul ng-controller="MyController">
<li ng-class="setColor(item.price)" ng-repeat="item in products">{{item.name}} — {{item.price}}</li>
</ul>
</div>
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function MyController($scope) {
$scope.setColor = function(price) {
alert(price);
}
$scope.products = [
{
'name' : 'Xbox',
'clearance' : true,
'price' : 30.99,
},
{
'name' : 'Xbox 360',
'clearance' : false,
'salesStatus' : 'old',
'price' : 99.99,
},
{
'name' : 'Xbox One',
'salesStatus' : 'new',
'price' : 50,
},
{
'name' : 'PS2',
'clearance' : true,
'price' : 79.99,
},
{
'name' : 'PS3',
'salesStatus' : 'old',
'price' : 99.99,
},
{
'name' : 'PS4',
'salesStatus' : 'new',
'price' : 20.99,
}
]
})
here is jsfiddle https://jsfiddle.net/tridip/ob8jh2o7/1/
UPDATE : My Objective
if price less than 50 then item color should be red. if price more than 50 then item color should be yellow and if price more than (50+(50*60/100)) then item color should be green. now tell me how could i achieve it with less iteration. guide me with best approach to complete it.
thanks
if fix it. here is my new fiddle link https://jsfiddle.net/tridip/ob8jh2o7/22/
Based on Using ng-class with a function call - called multiple times
You can try something like this if you are just modifying the class:
var colourMap = {
"30.99": "speciality1Class",
"99.99": "speciality2Class",
"50": "speciality3Class",
"79.99": "speciality4Class",
"20.99": "speciality5Class"
};
$scope.setColor = function(price) {
return colourMap[price];
}
fiddle: https://jsfiddle.net/ob8jh2o7/11/
However, if you are using an alert or log it is going to be called all those times because angulars use of dirty checking. If you are trying to fire an alert though, I would not use ng-class. You can read more about angulars dirty checking here - https://docs.angularjs.org/guide/scope#scope-life-cycle .
Angularjs uses a dirty-check approach, so it need to call all the filters to see if exists any change. After this it detect that have a change on one variable(the one that you typed) and then it execute all filters again to detect if has other changes.
The first call is from the watchers that are detecting the change. Because there is one then they need to be called again to see if is there news changes because a watcher can make changes.
<li ng-class="{red : item.price <= 50 , yellow: item.price > 50 && item.price <= 50 + 50*0.6, green: item.price > 50 + 50*0.6}" ng-repeat="item in products track by $index">{{item.name}} — {{item.price}}</li>
Edited Fiddle working: https://jsfiddle.net/ob8jh2o7/21/

isolate an ng-click inside of an ng-repeat loop to the element clicked

I apologize for the badly worded question, I am new to Angularjs. Working with ng-repeat and an ng-click that requests additional information from the controller. When performing the ng-click, all users are updated because they belong to the ng-repeat.
Is it possible to isolate the ng-click or set up the template so only the active user receives the data requested?
I tried some conditional logic with the results tag and the ng-click in the controller but was unsuccessful. Thanks!
jsfiddle here with example code: http://jsfiddle.net/2cd3tr55/2/
::HTML::
<div ng-controller="DomReadyCtrl">
<p>Hello {{test}}</p>
<div class="loop" ng-repeat='user in users track by $index'>
<div id="{{user.name}}">
<strong>user: </strong><em>{{user.name}} {{user.name == 'bert' ? '--toggle on bert' : ''}}</em>
<div>
<a ng-class="user{{user.id}}" href="javascript:void(0)" ng-click="GetUsername(user.id)">Get More Info:</a>
<br>
<span class="stats"> Months Worked: {{stats[0].months_worked}}, PTO Earned: {{stats[0].pto_earned}}</span>
</div>
</div>
<br>
</div>
</div>
::JS::
var app = angular.module('app', []);
app.controller('DomReadyCtrl', function($timeout, $scope){
$scope.users = [];
$scope.test = "World";
$scope.users = [
{'name':'al','id':'0'},
{'name':'bert','id':'1'},
{'name':'charles','id':'2'},
{'name':'dave','id':'3'},
{'name':'eddie','id':'4'},
{'name':'frank','id':'5'}
];
//console.log($scope.users);
document.body.setAttribute('class', 'red');
alert('Angular view not ready');
$scope.GetUsername = function(userID) { // ng-click gets new array data
$scope.stats = [];
if ( userID == '0' ) {
$scope.stats = [
{'months_worked' : '30', 'pto_earned': '0'}
]
// console.log($scope.stats);
}
if ( userID == '1' ) {
$scope.stats = [
{'months_worked' : '31', 'pto_earned': '1'}
]
}
if ( userID == '2' ) {
$scope.stats = [
{'months_worked' : '32', 'pto_earned': '2'}
]
}
if ( userID == '3' ) {
$scope.stats = [
{'months_worked' : '33', 'pto_earned': '3'}
]
}
if ( userID == '4' ) {
$scope.stats = [
{'months_worked' : '34', 'pto_earned': '4'}
]
}
if ( userID == '5' ) {
$scope.stats = [
{'months_worked' : '35', 'pto_earned': '5'}
]
}
}
});
angular.bootstrap(document.body, ['app']);
document.body.setAttribute('class', 'green');
$("#bert em").on('click',function() { //click on bert
$(this).toggleClass('orange');
$(this).children('div').toggleClass('hide');
});
I don't think the problem is with ng-click(). Instead, it appears to me the likely problem is that you only have one stats element used by all of the users' divs.
In your HTML you probably want to replace this:
<span class="stats"> Months Worked: {{stats[0].months_worked}}, PTO Earned: {{stats[0].pto_earned}}</span>
With something like this:
<span class="stats"> Months Worked: {{stats[$index].months_worked}}, PTO Earned: {{stats[$index].pto_earned}}</span>
And in your Javascript, for each userId case, you probably want something more like this:
$scope.stats[userId] = {'months_worked' : '30', 'pto_earned': '0'}
Or alternately, include the stats within the user object itself and pass the user object itself into the ng-click handler.

Angular-xeditable: Need a checklist that displays checked items

I would like to use a check list and show the user the boxes she has checked.
I am using this framework: http://vitalets.github.io/angular-xeditable/#checklist . See his example 'Checklist' versus his example 'Select multiple'. However, I do not want to display a link with a comma separated string, i.e., join(', '). I would like each selection to appear beneath the previous, in an ordered list or similar.
Pretty much copied from his examples, here are the guts of my controller:
$scope.userFeeds = {
feeds: {}
};
$scope.feedSource = [
{ id: 1, value: 'All MD' },
{ id: 2, value: 'All DE' },
{ id: 3, value: 'All DC' }
];
$scope.updateFeed = function (feedSource, option) {
$scope.userFeeds.feeds = [];
angular.forEach(option, function (v) {
var feedObj = $filter('filter')($scope.feedSource, { id: v });
$scope.userFeeds.feeds.push(feedObj[0]);
});
return $scope.userFeeds.feeds.length ? '' : 'Not set';
};
And here is my html:
<div ng-show="eventsForm.$visible"><h4>Select one or more feeds</h4>
<span editable-select="feedSource"
e-multiple
e-ng-options="feed.id as feed.value for feed in feedSource"
onbeforesave="updateFeed(feedSource, $data)">
</span>
</div>
<div ng-show="!eventsForm.$visible"><h4>Selected Source Feed(s)</h4>
<ul>
<li ng-repeat="feed in userFeeds.feeds">
{{ feed.value || 'empty' }}
</li>
<div ng-hide="userFeeds.feeds.length">No items found</div>
</ul>
</div>
My problem is - display works with editable-select and e-multiple, but not with editable-checklist. Swap it out and nothing is returned.
To workaround, I have tried dynamic html as in here With ng-bind-html-unsafe removed, how do I inject HTML? but I have considerable difficulties getting the page to react to a changed scope.
My goal is to allow a user to select from a checklist and then to display the checked items.
Try this fiddle: http://jsfiddle.net/mr0rotnv/15/
Your onbeforesave will need to return false, instead of empty string, to stop conflict with the model update from xEditable. (Example has onbeforesave and model binding working on the same variable)
return $scope.userFeeds.feeds.length ? false : 'Not set';
If you require to start in edit mode add the attribute shown="true" to the surrounding form element.
Code for completeness:
Controller:
$scope.userFeeds = {
feeds: []
};
$scope.feedSource = [
{ id: 1, value: 'All MD' },
{ id: 2, value: 'All DE' },
{ id: 3, value: 'All DC' }
];
$scope.updateFeed = function (feedSource, option) {
$scope.userFeeds.feeds = [];
angular.forEach(option, function (v) {
var feedObj = $filter('filter')($scope.feedSource, { id: v });
if (feedObj.length) { // stop nulls being added.
$scope.userFeeds.feeds.push(feedObj[0]);
}
});
return $scope.userFeeds.feeds.length ? false : 'Not set';
};
Html:
<div ng-show="editableForm.$visible">
<h4>Select one or more feeds</h4>
<span editable-checklist="feedSource"
e-ng-options="feed.id as feed.value for feed in feedSource"
onbeforesave="updateFeed(feedSource, $data)">
</span>
</div>
<div ng-show="!editableForm.$visible">
<h4>Selected Source Feed(s)</h4>
<ul>
<li ng-repeat="feed in userFeeds.feeds">{{ feed.value || 'empty' }}</li>
<div ng-hide="userFeeds.feeds.length">No items found</div>
</ul>
</div>
Css:
(Used to give the "edit view" a list appearance)
.editable-input label {display:block;}
Also there is the option of using a filter if you do not need to do any validation or start in edit mode.
Controller:
$scope.user = { status: [2, 3] };
$scope.statuses = [
{ value: 1, text: 'status1' },
{ value: 2, text: 'status2' },
{ value: 3, text: 'status3' }
];
$scope.filterStatus = function (obj) {
return $scope.user.status.indexOf(obj.value) > -1;
};
HTML:
<a href="#" editable-checklist="user.status" e-ng-options="s.value as s.text for s in statuses">
<ol>
<li ng-repeat="s in statuses | filter: filterStatus">{{ s.text }}</li>
</ol>
</a>

Validation not working (Directive scope.$error is not populated although ng-invalid class is applied to DOM element)

Updated: also, if anyone can tell me how to simplify my code, I would really appreciate that.
In short:
I have simple validation rule applied to element
<div ng-form='myForm'>
<input ng-model='row.item[0].field' required />
</div>
I also have style to color invalid entry
.ng-invalid { background:red }
And when I remove value from input box it's background color is changed, however neither row nor row.item , row.item[0] and row.item[0].field has $error property appeared. myForm.$error doesn't have anything as well.
So I cannot print validation message bellow input box
Longer explanation:
I could have much broader problem than that. Here is my setup (simplified) :
Markup:
Code:
function tableCtrl($scope) {
var fields = $scope.fields = [
{ name: 'events', required: true }
,{ name: 'subjects' }
,{ name: 'affected'}]
$scope.events = [{ name : 'e', type :'some', organ :'blood'
, items : [{ events : 1, subjects: 2, affected : 3 }
,{ events : 1, subjects: 2, affected : 3 }
,{ events : 1, subjects: 2, affected : 3 } ] }
, { name:'f', type : 'any', organ :'heart'
, items :[{ events : 1, subjects: 2, affected : 3 }
,{ events : 1, subjects: 2, affected : 3 }
,{ events : 1, subjects: 2, affected : 3 } ]}
, { name: 'g', type: 'all', organ :'skin'
, items : [{ events : 1, subjects: 2, affected : 3 }
,{ events : 1, subjects: 2, affected : 3 }
,{ events : 1, subjects: 2, affected : 3 } ]}]
}
angular.module('components').directive('editor', function ($compile) {
return {
scope : {
row : '=editor'
, fields : '=fields'
},
terminal:true,
link: function (scope, element, attrs) {
var tmpl = ''
for (var g in row.items ) {
var itemPath = 'row.items['+g+']'
for (var f in scope.fields) {
tmpl += '<td><input type="number" ng-model="'+itemPath+'.'+scope.fields[f].name + '"' +
' min="0" ' +
(scope.fields[f].required? ' required ' : '' )+
' /></td>'
}
}
var newElement = angular.element(tmpl);
$compile(newElement)(scope);
element.replaceWith(newElement);
}
}
So I'm creating input boxes dynamically.
The validation is related to ng-form and ng-model directive which means you need either a <form> element or <ng-form element with a name for validation to work.
Then you can access the valid state in the scope using formname.$error.
<form name="myform">
<input ng-model='row.item[0].field' required />
<input type="submit" ng-disabled="myform.$error" value="Save" />
</form>
Try to compile the new element on the parent scope, not on the isolated scope. It worked on my case.
$compile(newElement)(scope.$parent);

Resources