How can I add a join function to multiple ng-show items? - angularjs

I have four conditional ng-show elements:
Add
<strong ng-show="current_user.candidate.skills.length == 0">skills,</strong>
<strong ng-show="current_user.candidate.roles.length == 0">roles,</strong>
<strong ng-show="current_user.candidate.projects.length == 0">projects,</strong>
<strong ng-show="current_user.candidate.qualifications.length == 0">qualifications,</strong>
to increase your chances.
I want to add a .join(', ') function rather than have the commas after each item. I'd also like to add an 'and' between the last two items if items >= 2. What's the most Angular way to do this?

Related

Star-rating component logic implementation in react

I am working on a star-rating component in react. I have implemented successfully the full and empty star rating but i got stuck in displaying half stars. I came up with a logic i tried many times but didn't find a way to implement that logic. Currently this component is just displaying star-ratings without any click functionality.
I want to implement this logic:
Suppose we have selectedStars as 2.5 and totalStars as 5 and we want to display two full stars and a half star and the rest empty stars. I separated the selectedStars into two parts one containing the integer part and other containing the floating part. I have successfully separated the two parts using
firstHalf = Math.floor(selectedStars) it will give as a result 2
secondHalf = selectedStars % 1 it will give as a result 0.5
also i have converted totalStars into an array using [...Array(totalStars)] so as to represent five stars in total.
and i am running the loop on indexes.
with the both parts i want to implement this if else ladder which is as follows:
if(index < firstHalf) then use font-awesome "fa fa-star" icon
else if(secondHalf === 0.5) then use font-awesome "fa fa-star-half-o" icon and increment secondHalf i did this because there will be only one half star and next time when it checks for the secondHalf value the condition comes out to be false and it will move to the next statement.
else use font-awesome "fa fa-star-o" icon to represent empty stars.
I hope you understand what i want to implement here.
This is how I implemented your secondMethod in the codesandbox you provided:
secondMethod = () => {
// implement the code for full, empty and half stars here.
const { selectedStars, totalStars } = this.state;
return [...Array(totalStars)].map((el, i) =>
// check if current star should be half
i < selectedStars && i + 1 > selectedStars ?
<i key={i} className="fa fa-star-half-o" />
// not half, so check if current star should be full
: i < selectedStars ? <i key={i} className="fa fa-star" />
// else, current star should be empty
: <i key={i} className="fa fa-star-o" />
);
};

How do I set a class based on a child element's state with Angular?

I am trying to display a results 'table' (built with DIVs as it happens) using Angular. Data looks somethingof it like this:
[['sydney','hotel','2','5','1'],
['sydney','bar','6','5','2'],
['sydney','stand','2','7','3'],
['melbourne','hotel','2','5','1'],
['melbourne','bar','8','0','1']]
What I want firstly is to suppress the repeating city name so that the first row says 'sydney' at the start but the second row and third row don't. Then the fourth says 'melbourne' and the fifth says nothing.
I've achieved this using markup like this:
<div class="row-container"
ng-repeat="row in resultsRows"
<div
ng-repeat="cell in row track by $index"
ng-bind="showValue( cell )">
</div>
</div>
The showValue() function in the controller looks like this:
$scope.currentCityName = '';
function showValue( val ) {
var outValue = '';
if (this.$index === 0) {
if (val === $scope.currentCityName) {
outValue = '';
} else {
$scope.currentCityName = val;
outValue = val;
}
} else {
outValue = val;
}
return outValue;
}
Maybe that's a bit clunky but it works and I get:
sydney hotel 2 5 1
bar 6 5 2
stand 2 7 3
melbourne hotel 2 5 1
bar 8 0 1
Now, though, I want rows that have the city name in them to have a different background colour.
What I think I want is for any 'TR' DIV (I call it that because it contains the left-floated 'TD' DIVs with the data points in them) to check if its first child DIV is not empty (because it has the city name in it) and, if so, to colour its background.
My question is: how do I do that with Angular? Or am I missing another trick..?
How do I get an item in an ng-repeat loop to interrogate a child element?
You are using ng-repeat, which has built-in values like $even and $odd:
$even boolean true if the iterator position $index is even (otherwise false).
$odd boolean true if the iterator position $index is odd (otherwise false).
Use ng-class to give different classed depending on $even and $odd.

ng-class based on variable value

I have a variable with 4 possible values and i want to add a class for the first 3 variables and another for first 2 variables, also the requirement will some time change to one class for two possible value and another for other value
so if i give
<span ng-class="{'yes' : provisioned=='active',
'yes': provisioned=='cannot_delete_edit',
'no': provisioned=='cannot_delete_edit_upload',
'no': provisioned=='inactive'}" class="flag">
</span>
it is not working how can i solve this
You should have each class listed only once:
<span ng-class="{'yes': provisioned=='active' || provisioned == 'cannot_delete_edit', 'no': provisioned=='cannot_delete_edit_upload' || provisioned=='inactive', 'flag': true}"></span>
If your span has only two options, you can use this instead:
<span ng-class="(provisioned=='active' || provisioned == 'cannot_delete_edit') ?
'yes' : 'no'">...</span>
But this still leaves hard-coded values in the HTML. Instead, I would recommend leaving the data in the controller:
$scope.provisioned = (provisioned=='active' || provisioned == 'cannot_delete_edit');
and then using
<span ng-class="provisioned ? 'yes' : 'no'">...</span>

Ng-Repeat array to rows and columns

Thanks for taking the time to read this, I was wondering how I might be able to use ng-repeat to create a grid like box of options. I would like to take an array repeat nth number of items and then move to the next row or column until all items are listed. e.g.
assuming I had an array like [opt1,opt2,opt3,opt4,opt5,opt6,opt7] I would like to display it like this:
opt1 opt2 opt3
opt4 opt5 opt6
opt7
This is more a styling/markup problem than an AngularJS one. If you really want to, you can do:
<span ng:repeat="(index, value) in array">
{{value}}<br ng:show="(index+1)%3==0" />
</span>
http://jsfiddle.net/JG3A5/
Sorry for my HAML and Bootstrap3:
.row
.col-lg-4
%div{'ng:repeat' => "item in array.slice(0, array.length / 3)"}
{{item}}
.col-lg-4
%div{'ng:repeat' => "item in array.slice(array.length / 3, array.length * 2/3)"}
{{item}}
.col-lg-4
%div{'ng:repeat' => "item in array.slice(array.length * 2/3, array.length)"}
{{item}}
There is another version, with possibility to use filters:
<div class="row">
<div class="col-md-4" ng-repeat="remainder in [0,1,2]">
<span ng-repeat="item in array" ng-if="$index % 3 == remainder">{{item}}</span>
</div>
</div>
If all of your items are in one single array, your best bet is to make a grid in CSS. This article should be helpful: http://css-tricks.com/dont-overthink-it-grids/
You can use $index from ng-repeat to apply the correct class for your column (in this case a 4 column grid):
<div class="col-{{ $index % 4 }}"></div>
If you have a 2 dimensional array (split into rows and columns) that opens up more possibilities like actually using an HTML table.
I find it easier to simply use ng-repeat combined with ng-if and offsetting any indexes using $index. Mind the jade below:
div(ng-repeat="product in products")
div.row(ng-if="$index % 2 === 0")
div.col(ng-init="p1 = products[$index]")
span p1.Title
div.col(ng-if="products.length > $index + 1", ng-init="p2 = products[$index + 1]")
span p2.Title
div.col(ng-if="products.length <= $index + 1")
Between Performance, Dynamics and Readability
It seems putting the logic in your JavaScript is the best method. I would just bite-the-bullet and look into:
function listToMatrix(list, n) {
var grid = [], i = 0, x = list.length, col, row = -1;
for (var i = 0; i < x; i++) {
col = i % n;
if (col === 0) {
grid[++row] = [];
}
grid[row][col] = list[i];
}
return grid;
}
var matrix = listToMatrix(lists, 3);
console.log('#RedPill', matrix);
# Params: (list, n)
Where list is any array and n is an arbitrary number of columns desired per row
# Return: A matroid
# Note: This function is designed to orient a matroid based upon an arbitrary number of columns with variance in its number of rows. In other words, x = desired-columns, y = n.
You can then create an angular filter to handle this:
Filter:
angular.module('lists', []).filter('matrical', function() {
return function(list, columns) {
return listToMatrix(list, columns);
};
});
Controller:
function listOfListsController($scope) {
$scope.lists = $http.get('/lists');
}
View:
<div class="row" ng-repeat="row in (lists | matrical:3)">
<div class="col col-33" ng-repeat="list in row">{{list.name}}</div>
</div>
With this, you can see you get n number of rows -- each containing "3" columns. When you change the number of desired columns, you'll notice the number of rows changes accordingly (assuming the list-length is always the same ;)).
Here's a fiddle.
Note, that you get the ol' Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!. This is because Angular is recalling the matrical function upon every iteration. Allegedly, you can use the as results alias to prevent Angular from reevaluating the collection, but I had no luck. For this, it may be better to filter the grid inside of your controller and use that value for your repeater: $filter('matrical')(items) -- but please post back if you come across an elegant way of filtering it in the ng-repeat.
I would stress, again, you're probably heading down a dark alley by trying to write the logic in your view -- but I encourage you to try it in your view if you haven't already.
Edit
The use of this algorithm should be combined with a Matrical Data-Structure to provide methods of push, pop, splice, and additional methods -- in tandem with appropriate logic to complement Bi-Directional Data-Binding if desired. In other words, data-binding will not work out of the box (of course) as when a new item is added to your list, a reevaluation of the entire list must take place to keep the matrix's structural integrity.
Suggestion: Use the $filter('matrical')($scope.list) syntax in combination with $scope.$watch and recompile/calculate item-positions for the matrix.
Cheers!

Angular expression evaluate equal to

I'd like to make something like this.
<h3 ng-show="{{mode == 'create'}}">Create Vacancy</h3>
<h3 ng-show="{{mode == 'edit'}}">Edit this Vacancy</h3>
Where $scope.mode is either "create" or "edit".
How do I do this? Nothing I'm trying is working.
ng-show evals expression itself, so don't use interpolated text. Update your code to:
<h3 ng-show="mode == 'create'">Create Vacancy</h3>
<h3 ng-show="mode == 'edit'">Edit this Vacancy</h3>

Resources