I want to check at least one value in ng-repeat, if found, then to display <div> class - angularjs-ng-repeat

In my ng-repeat, scored/not scored are there. I want to display <div> class if at least one item in the ng-repeat has "Not Scored"

You should be determining whether or not you are displaying that div inside your controller. Doing it within the ng-repeat would mean you would have logic in your view and that's just not good practice. Here is a simple example on how to accomplish what you're wanting.
In your controller:
$scope.showDiv = false;
$scope.getItems = function () {
// fetch items via ajax...
for (var i = 0; i < data.items.length; i++) {
if (data.items[i].foo == 'Not Scored') {
showDiv = true;
}
}
}
And on your view:
<div ng-show="showDiv">
// do your ng-repeat here
</div>

Related

Use methods and computed properties in child component

In my List component I have a method which count the length of the array within certain categories.
methods: {
getLengthofaCategory(cat) {
const LowerCaseSearch = this.search.toLowerCase();
let categoryCount = this.products.filter(
product =>
(product.name.toLowerCase().includes(LowerCaseSearch) ||
product.category.toLowerCase().includes(LowerCaseSearch)) &&
(!this.checked.length || this.checked.includes(product.category)) &&
product.category === cat
);
return categoryCount.length;
}
}
See here my setup in this sandbox.
But I want the values next to the checkboxes (which are coming from my CheckBox component).
How do I get the logic from the method getLengthofaCategory into my CheckBox component?
So I am able to use {{ getLengthofaCategory('tennis') }} in the v-for loop, inside the CheckBox component. And then maybe I can also use category.value instead of hardcoding e.g 'tennis' as the paramater?
In your list.vue, you can use the already created computed function filteredData instead of doing the filter again. This saves some performance because in Vue, computed properties are "cached" once run.
So you can create a new computed function that creates an object with keys per category and value can either be just the amount or an array of products in this category.
I would then pass this computed value to the CheckBox component via a prop, then inside the CheckBox component, you can display the .length or value regarding how many items each category has:
List.vue:
computed: {
//...
amountPerCategory() {
return this.filteredData.reduce((categories, product) => {
if (!(product.category in categories)) {
categories[product.category] = [];
}
categories[product.category].push(product);
return categories;
}, {});
}
}
CheckBox.vue:
<span class="ml-2 text-gray-700 capitalize">{{ category.value }}</span> -
<span
v-if="count[category.value]"
class="ml-2 text-gray-700 capitalize"
>{{ count[category.value].length }}</span>
count: {
type: Object,
default: () => ({})
}
https://codesandbox.io/s/admiring-ellis-4hojl?file=/src/components/CheckBox.vue

Knockout.js ObservableArray sort not updating UI

I have a Knockout observable array that refuses to update the UI (a jquery Accordion) to which it is bound after a .sort() call, but happily updates the UI after a .reverse() call - I've been banging my head against this problem for days - can't seem to find an answer... help!
Container View Model - implements the observableArray Property :
function DataTextsKOViewModel( jsonTexts ) {
var self = this;
// Texts array
self.texts = ko.observableArray();
// Build from json data array
for (var i = 0; i < jsonTexts.AuthorityTexts.length; i++) {
var jsontext = jsonTexts.AuthorityTexts[i];
// Push Text VModel objects onto the KO observable array list ..
self.texts.push(
new DataTextKOViewModel( jsontext )
);
}
}
Array Object Model - These are the objects which are sorted:
// Single data text view model
function DataTextKOViewModel(jsonText) {
// Other properties omitted for brevity
this.ListOrder = ko.observable(jsonText.ListOrder);
}
Custom Sort Function :
function textListOrderCompare(l, r) {
// Ascending sort
var retval = ((l.ListOrder() == r.ListOrder()) ? 0
: ((l.ListOrder() > r.ListOrder()) ? 1 : -1));
return retval;
}
Binding Markup :
<!-- ko foreach: texts -->
<div class="group" data-bind="attr:{'id': clientId() }">
<h3 data-bind="attr:{'dataKey': responsibilityId() }">
<span data-bind="text: responsibilitySectionHeader"></span>
</h3>
<div>
<!-- section content goes here -->
</div>
</div>
When User Elects to sort:
myDataTextsKOViewModel.rollbackChanges();
dataTextsViewModel.texts.sort(textListOrderCompare);
// UI Never updates - but I've checked console output to ensure that the array
/ /sorts correctly
dataTextsViewModel.texts.sort(textListOrderCompare);
// UI updates with items in reverse order
Any help you can give me would be most appreciated.
EDIT: Should have mentioned - I already call valueHasMutated() on the observable array property after the .sort()! - Andrew
Try to call valueHasMutated function after sorting:
dataTextsViewModel.texts.sort(textListOrderCompare);
dataTextsViewModel.texts.valueHasMutated();
dataTextsViewModel.texts(dataTextsViewModel.texts().sort(textListOrderCompare));
this way you change observable. Other way was changing the array inside and didn't trigger the change.

AngularJS Form Validation inside an ng-repeat

So I am trying to validate the input of one item inside of an ng-repeat. For examples sake lets say that I have 5 items (1,2,3,4,5) and I only want to validate the form if the 4th item is selected.
I have used ng-pattern before to validate forms, but not one that had a dropdown menu to select item.name
I have included the regex I would like the 4th item to be validated with inside the ng-pattern.
<div>
<select name="name" ng-model="item.name" ng-options="item for item in items" required></select>
</div>
<div>
<input name="results" type="text" ng-model="item.results" ng-pattern="/^\d\d\d\/\d\d\d/" required>
</div>
Any suggestions as to the correct way to validate this situation would be greatly appreciated. I have thought about creating a directive to validate this, but that feels like is an overly complicated solution to this since I would not use the directive more than once in this app.
//////////////////////////////////////////////////
It wouldn't let me answer my own question so here is the answer I figured out.
What I ended up having to do was use ng-pattern and pass it a function.
<input name="results" type="text" ng-model="vital.results" ng-pattern="vitalRegEx()" required>
Here is the controller code
$scope.item4RegEx = /^\d{2,3}\/\d{2,3}$/;
$scope.itemRegEx = function() {
if($scope.item && $scope.item.name === "fourth item")
return $scope.item4RegEx;
else return (/^$/);
};
or else...
add ng-change directive on the select dropdown which calls a Controller method and that controller method sets a flag whether to validate form or not.
eg.
<select ng-change="checkIfFormShouldbeValidated()" ng-model="item.name"></select>
// Inside controller
$scope.checkIfFromShouldBeValidated = function(){
if( $scope.item.name == 4th Item ) $scope.shouldValidate = true;
else $scope.shouldValidate = false;
};
$scope.formSubmit = function(){
if(($scope.shouldValidate && form.$valid) || (!$scope.shouldValidate)){
// Submit Form
}
};
See if it helps.
I wrote this recursive function inside my controller to check the validity of all child scopes.
function allValid(scope) {
var valid = true;
if (scope.$$childHead) {
valid = valid && allValid(scope.$$childHead);
}
if (scope.$$nextSibling) {
valid = valid && allValid(scope.$$nextSibling);
}
if (scope.scorePlannerForm) {
valid = valid && scope.myForm.$valid;
}
return valid;
}
Then in my controller I check this with the controller scope.
function formSubmit() {
if (allValid($scope)) {
// perform save
}
}

Coloring a Partial view in MVC 3

In my view, I use a partial view with a list of objects from my model as follows:
#foreach (var item in Model.MyObjectList)
{
#Html.Partial("DisplayObject", item)
}
This forms a grid pattern down my main view, 1 row for each object.
I'd like to stripe them using normal method of odd rows one colour, even rows another. (like this for example.
Usually you'd do this by doing some kind of mod calculation.
The question is I can't figure out how to do this without passing in a row number in the item into the partial view.
Is there an easier way? Html.Partial does not have any html attributes I can hook into.
I could of course put a table around the partial and stripe it that way, but would prefer not to.
If you can limit support to CSS3 you can use the :nth-child(odd) and :nth-child(even) rules - as shown on this page from W3C - http://www.w3.org/Style/Examples/007/evenodd.en.html
Those examples show how to use it on tr tags - but it applies to anything that you can apply a selector to:
<style type="text/css">
div p:nth-child(odd) { color:red; }
div p:nth-child(even) { color:green; }
</style>
<div>
<p>first</p>
<p>second</p>
<p>third</p>
</div>
I think you should pass the information in the model that is passed to the partial view OR wrap the partial view in an element and apply the correct css to it...like:
#foreach (var item in Model.MyObjectList) {
<li class="odd|even">
#Html.Partial("DisplayObject", item)
</li>
}
Add the row number as a property to the definition of your class that defines each 'item'.
Use that property in the partial view to determine if its an odd or even row.
Pass the Mode value through ViewBag from the main view to partial.
#foreach (var item in Model.MyObjectList)
{
if(ViewBag.Mode == "odd")
{
ViewBag.Mode = "even";
}
else
{
ViewBag.Mode = "odd";
}
#Html.Partial("DisplayObject", item)
}

Sorting Div's With PrototypeJS

I am looking for some help in sorting div's with PrototypeJS. Here is what I have so far:
document.observe('dom:loaded',function(){
$$('.sortcol').invoke('observe', 'click', function() {
if (this.hasClassName('desc')) {
var desc = false;
this.removeClassName('desc');
} else {
var desc = true;
this.addClassName('desc');
}
var colname = this.className;
var contentid = this.up(2).id;
sortColumn(contentid,colname,desc);
});
});
function sortColumn(contentid,colname,desc) {
$$('#'+contentid).select('.'+colname).sort(function(a,b){
if (desc) {
return (a.text.toLowerCase() >= b.text.toLowerCase() ) ? -1 : 1;
} else {
return (a.text.toLowerCase() < b.text.toLowerCase() ) ? -1 : 1;
}
});
}
Example data:
<div id="contentbox_Users" class="userList">
<div class="userListHeader">
<div class="userListHeaderCell col1">First Name</div>
<div class="userListHeaderCell col2">Last Name</div>
</div>
<div id="contentbox_People">
<div class="userListRow">
<div class="userListCell col1">John</div>
<div class="userListCell col2">Smith</div>
</div>
<div class="userListRow">
<div class="userListCell col1">Bob</div>
<div class="userListCell col2">Ray</div>
</div>
<div class="userListRow">
<div class="userListCell col1">Fred</div>
<div class="userListCell col2">Jones</div>
</div>
</div>
</div>
Basically anything with a class "sortcol", when it is clicked, I want it to sort by the column name clicked (class). The first issue is I need to be able to get the class name correctly when there is multiple classes. The classes are all like col1, col2, etc. How would I find the correct class?
The second thing is changing sortColumn so that it keeps column data together (each row is wrapped by another div) and output the result, replacing the current data.
This needs to be done in prototypejs and I can't change the code to tables.
Thanks in advance for the help.
For the first part of your question it would be much easier if the column name was it's own attribute like rel or data-*, but you say you cannot change the HTML. It is possible to pick out the likeliest class with regex...
var colname = this.className.match(/\bcol\d+\b/).first()
But this is unnecessary if we assume every row has the same columns in the same order. This would be a safer assumption if a table were used.
var colnumber = this.up().childElements().indexOf(this);
The second part of your question is easy, just sort the rows instead of the cells.
Your draft sortColumn function doesn't actually change the elements - select returns an array of element references, not their container - so you need to do something with the resulting array. Luckily any append or insert action of an element causes it to be removed from it's parent first, so simply append them once more and they'll assume the correct order. No replacing is needed, I've seen libraries that bizarrely convert the elements to HTML, concatenate that then reinsert it!?!
The following has been tested.
document.observe('dom:loaded',function() {
$$('.userListHeaderCell').invoke('observe', 'click', function() {
this.toggleClassName('desc');
var colnumber = this.up().childElements().indexOf(this);
var content = this.up(2); // use the element directly instead of it's ID
sortColumn(content, colnumber, this.hasClassName('desc'));
});
});
function sortColumn(content, colnumber, desc) {
content.select('.userListRow').sort(function(a,b){
var atext = a.down(colnumber).innerHTML.stripTags().toLowerCase();
var btext = b.down(colnumber).innerHTML.stripTags().toLowerCase();
return atext.localeCompare(btext) * (desc ? -1 : 1);
}).each(Element.prototype.appendChild, content);
}
This to me seems like you are creating tabular data. So why not use a table? And once you use a table, there are many sorting scripts out there. A quick google came up with this one.

Resources