Apply CSS styling to a mapped item - javascript

I have a list of items that are checkboxes for a settings page. These are stored in a const items like so:
const ITEMS = [
["youtube", "YouTube"],
["videos", "Videos"],
["facebook", "Facebook"],
["settings", "Settings"],
]
and currently, these four items are just listed as list items. What I have right now is this:
but what I want is this:
I was thinking of applying a check to see if the sub-category belongs to that parent category, and apply some type of indentation to the sub-categories. Is that possible to do through a map (which is how I'm iterating through this array)? Or is there a smarter, more efficient way to solve this issue?
Here's how I render my checkboxes:
item: function(i) {
return (
<div className="checkbox">
<label>
<input type="checkbox" checked={this.state.items[i[0]]}/>
{i[1]}
</label>
</div>
)
}
render: function() {
return (
<div className="col-sm-12">
{_(ITEMS).map(this.item, this)}
</div>
)
}

I would recommend you to use objects in an array. So you're able to map more than just property to each item. For accessing it only with normal Javascript I would use a for-Loop because of its compability with older browsers. An example I made, can be found here:
https://jsfiddle.net/morrisjdev/vjb0qukb/

With some 'dirty' code, you could use this: https://jsfiddle.net/1sw1uhan/
const ITEMS = [
["youtube", "YouTube"],
["videos", "Videos"],
["facebook", "Facebook"],
["settings", "Settings"],
]
var list = $('<ul>');
$.each(ITEMS, function( index, value ) {
if ((index+1)%2 == 0 && index != 0){
var sublist = $('<ul>').append($('<li>').text(value[1]).attr('id', value[0]));
} else {
var sublist = $('<li>').text(value[1]).attr('id', value[0]);
}
list.append(sublist);
})
$('#somediv').append(list);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="somediv">
</div>

Related

Computed, print items on change without duplicate

I'm trying to show items in a table every time the list of item changes. I've got a function and a computed but I'm not quiet sure if I'm doing it right.
Function(){
Every time a new value comes in: changeList.push(item);
}
Then I have this computed
Computed:
changedData: function(){
return this.changeList;
}
HTML
<tr v-for="change in changedData">
<td>change.value</td>
<tr>
It does print out every item in the list when it is changed, but the thing is I don't want it to print out the items that already printed out, only new items.
EDIT: Found the problem (push function)
for(index in question.Answers){
if(question.Answers[index].Selected === "selected" &&
question.Answers[index].Value === savedQuestion.Value){
this.myList.push({newValue: question.Answers[index].Value, oldValue:
savedQuestion.Value});
}
}
This will add all the questions with their value regardless if the list already contains the same question with the exact same values.
So to achieve this you can check in the array if the object with same values is present or not.If not than only push the values.
Below is the updated code.
const search = (newVal,oldVal) => array.find(element => (element.newValue === newVal && element.oldValue === oldVal));
for(index in question.Answers){
if(!search(question.Answers[index].Value,savedQuestion.Value))
if(question.Answers[index].Selected === "selected" &&
question.Answers[index].Value === savedQuestion.Value){
this.myList.push({newValue: question.Answers[index].Value, oldValue:
savedQuestion.Value});
}
}
In your code computed is actually not needed.Here is the basic example of adding dynamic values into the list at runtime.
https://codepen.io/anon/pen/LqKjMM?editors=1111
Template code =>
<script src="//vuejs.org/js/vue.js"></script>
<h1>Example of managing a Vue.js list</h1>
<div id="products">
<vue-products></vue-products>
</div>
<script type="text/template" id='vue-products-template'>
<div>
<form v-on:submit.prevent="addProduct">
<input type="text" v-model="productName">
<input type="submit" value="Add"></input>
</form>
<ul>
<li v-for="name in productNames">{{name}}</li>
</ul>
</div>
</script>
Script code =>
Vue.component('vue-products', {
template: '#vue-products-template',
data: function() {
return {
productName: "",
productNames: ['booze', 'tums', 'peas', 'short wave radio'],
}
},
methods: {
addProduct: function() {
this.productNames.push(this.productName)
this.productName = ""
}
}
})
$(function() {
new Vue({el: '#products', data: {}})
});

Render components based on the data from a multidimensional array in React

I have an array with items which can have even or odd number of items. I made a function which puts each two elements in their own array inside a main array, so it looks like this at the end;
items array: [{}, {}, {}, {}]
returned array: [[{}, {}], [{}, {}]]
items array: [{}, {}, {}]
returned array: [[{}, {}], [{}, undefined]]
I did this because I want to render each Bootstrap row with two columns on the page. Now, I'm not sure how to implement mapping through this array. To a certain extent I know how to do this;
Map through returned array.
If second element in current array is undefined return a row with just one item.
If both elements are defined in current array return a row with both items.
But by React rules I need to add additional key attributes to the elements I return with map so I would need to somehow keep the track of index variable. What would be the efficient way to do this?
I can't think of a nice way to map your original array, but you could use a for loop and increment by 2 each iteration and just check if the second element is truthy before using it.
Example
class App extends React.Component {
render() {
const content = [];
for (let i = 0; i < itemsArray.length; i += 2) {
content.push(
<div class="row" key={i}>
<div class="col-md-6">
<div class="option correct-option">{itemsArray[i].text}</div>
</div>
{itemsArray[i + 1] && (
<div class="col-md-6">
<div class="option correct-option">{itemsArray[i + 1].text}</div>
</div>
)}
</div>
);
}
return <div>{content}</div>;
}
}
If you want to use the array of arrays, you could map it and just check if the second element in the array is truthy before using it.
Example
class App extends React.Component {
render() {
return (
<div>
{itemsArray.map((items, index) => {
<div class="row" key={index}>
<div class="col-md-6">
<div class="option correct-option">{items[0].text}</div>
</div>
{items[1] && (
<div class="col-md-6">
<div class="option correct-option">{items[1].text}</div>
</div>
)}
</div>;
})}
</div>
);
}
}

Using AngularJS to create an instant search by querying an array

This is going to be a rather longwinded question, so please bear with me...
I have an array of about 25-30 items. They are sorted through various filters such as brand, type, material, size, etc.. How can I go about building a searchable filter. All of the ones I've seen just include a filter:query | in their filters. However I can't get mine to query my existing array.
Here is what my array looks like, only going to show 1 item to keep size down..
$scope.products = [
{
src: 'images/img/image1.jpg',
name: 'XXX-1A',
brand: 'Brand A',
material: 'dry',
size: '00',
type: 'dry pipe',
color:'red'
}];
Function for filtering (only included 1 to save space):
$scope.brandIncludes = [];
$scope.includeBrand = function(brand) {
var i = $.inArray(brand, $scope.brandIncludes);
if (i > -1) {
$scope.brandIncludes.splice(i, 1);
} else {
$scope.brandIncludes.push(brand);
}
}
$scope.brandFilter = function(products) {
if ($scope.brandIncludes.length > 0) {
if ($.inArray(products.brand, $scope.brandIncludes) < 0)
return;
}
return true;
}
This is what I am using to filter from the HTML, I am using checkboxes to select each filter:
<div class="info" ng-repeat="p in products |
filter:brandFilter |
filter:materialFilter |
filter:typeFilter |
filter:styleFilter">
</div>
My search bar mark up:
<div class="filtering">
<div class="search-sect">
<input name="dbQuery" type="text" placeholder="Search pieces" class="search-input" ng-model="query"/>
</div>
One of the filter's mark up:
<input type="checkbox" ng-click="includeStyle('adaptor')"/>Adaptor<br>
Now that you have all the code, here are some of the things I've tried that don't seem to be running right:
My Attempt:
Search bar:
<input type="text" id="query" ng-model="query"/>
Filter:
<li ng-repeat="p in products | filter:query | orderBy: orderList">
I understand that to some experienced with angular, this is a relatively easy task, but I am just learning and can't seem to wrap my head around searching a query. It's probably a simple solution that I am overlooking. This is my first Angular app and I am trying to bite off more than I can chew in order to learn more.
I appreciate all responses, thanks in advance!
As per request: CodePen
The simple built-in angular filter is not smart enough to to work with your checkbox design, so try writing a custom filter. You will need to bind the checkboxes you mentioned to variables in your scope, e.g. brandFilterIsEnabled. See the tutorial for writing custom filters. Here is a working example.
var myApp = angular.module('myApp', []);
myApp.controller('ctrl', function ($scope) {
$scope.items = [{
name:'foo',
color:'red'
},{
name:'bar',
color:'blue'
},{
name:'baz',
color:'green'
}];
$scope.searchNames = true;
$scope.searchColors = true;
$scope.$watch('searchColors', function(){
$scope.searchKeys = [ $scope.searchNames ? 'name' : null, $scope.searchColors ? 'color' : null ];
});
$scope.$watch('searchNames', function(){
$scope.searchKeys = [ $scope.searchNames ? 'name' : null, $scope.searchColors ? 'color' : null ];
});
});
myApp.filter('advancedSearch', function($filter) {
return function(data, keys, query) {
results = [];
if( !query ){
return data;
} else {
angular.forEach( data, function( obj ){
var matched = false;
angular.forEach( keys, function( key ){
if( obj[key] ){
// match values using angular's built-in filter
if ($filter('filter')([obj[key]], query).length > 0){
// don't add objects to results twice if multiple
// keys have values that match query
if( !matched ) {
results.push(obj);
}
matched = true;
}
}
});
});
}
return results;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html ng-app="myApp">
<div ng-controller="ctrl">
<input type='checkbox' ng-model='searchNames'>search names</input>
<input type='checkbox' ng-model='searchColors'>search colors</input>
<input type='text' ng-model='query'>search objects</input>
<ul>
<li ng-repeat="item in items | advancedSearch : searchKeys : query">
<span style="color:{{item.color}}">{{item.name}}</span>
</li>
</ul>
</div>
</html>

Finding item of array base on the ng-repeater index in Angular

In my application i have 2 array of object.layout array is for creating twitter bootstrap layout.this array is like below :
$scope.layout = [
{c:[{size:12}]},
{c:[{size:2},{size:3},{size:4},{size:3}]},
{c:[{size:3},{size:5},{size:4}]}
];
you can see how this array work in this jsbin.the other array is items array and this array is like below:
$scope.items =[
{row:1,column:0,names:['Jack','Daniel']},
{row:3,column:3,names:['Eli','Bill']},
{row:2,column:1,names:['Fred','David']}
];
and this is the repeater that i used :
<div ng-repeat="(ri,r) in layout" class="row">
<div ng-repeat="(ci,c) in r.c" class="col-md-{{c.size}} col-sm-{{c.size}} col-xs-{{c.size}} col-lg-{{c.size}} bi"> Row{{ri}}-Column{{ci}}
//Maybe other repeater come here
</div>
</div>
now i want when i want to display Jack , Daniel in row 1 column 0 and this 1 and 0 is r and c in repeater of first and second repeater.so when the repeater create row 2 column 1 also repeat on $scop.item and find the related names. but i don't know how to find items in $scope.item.and this is my jsbin
You can do something like this:
<div ng-repeat="(ri,r) in layout" class="row">
<div ng-repeat="(ci,c) in r.c" class="col-md-{{c.size}} col-sm-{{c.size}} col-xs-{{c.size}} col-lg-{{c.size}} bi">
{{getNames(ri, ci)}}
</div>
</div>
Where getNames is defined in controller:
$scope.getNames = function(r, c) {
var items = $scope.items;
for (var i = 0; i < items.length; i++) {
if (items[i].row == r && items[i].column == c) {
return items[i].names;
}
}
return '';
};
Demo: http://jsbin.com/sumuwigo/1/edit

Angularjs ng-repeat with conditions

Lets say I have 10 articles objects array and each with their own article title in it ( assume some of them has the same title )
when i do ng-repeat="art in articles" and {{ art.article_title }} it will print the title 10 times which is not what I want.
I want to do something like
Title-1:
article 1
article 2
article 3
Title-2:
article 4
article 5......
something like that if articles share the same title.
Thanks
You should write a custom filter, then you will be able to proceed like this:
<li ng-repeat="unique_article in articles|dedup">
{{unique_article.article_title}}
<span ng-repeat="related in unique_article.related">
Article {{related.id}}
</span>
</li>
Your filter may look for example like this (assuming your articles are sorted by title):
.filter('dedup', function() {
return function(articles) {
var deduped = [];
var last_article = null;
for(var i=0,max=articles.length;i<max;i++) {
var article = articles[i];
if(!last_article || last_article.article_title !== article.article_title)
{
article.related = [];
deduped.push(article);
last_article = article;
} else {
last_article.related.push(article);
}
}
return deduped;
};
});
(I did not test it, just written it ad hoc as a quick example, also if your articles are not sorted by title you will have to modify it)
Maybe re-thinking it would help, the ideal way to do this would be to re-arrange your object so that the articles fall under the titles, like so.
var arrangeArticles = function() {
var result = {};
angular.forEach($scope.articles, function( article ) {
var title = article.article_title;
if( !result[title] ) {
result[title] = [article];
} else {
result[title].push(article);
}
});
$scope.articles = result;
$scope.$apply(); // Might be needed
};
I don't think that you can do this in the ng-repeat, with the layout that you expressed.
Then you would need to change your repeat to something like this
<div ng-repeat="(title, group) in articles">
{{title}}
<div ng-repeat="article in group">
{{article.description}}
</div>
</div>

Categories