I'm trying to filter categories when links.items contains a specific string.
const links = [
{
id: 1,
category: 'Category 1',
items: [
{
id: 1,
name: 'Link1',
url: 'https://#',
info: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
},
{
id: 2,
name: 'Link2',
url: 'https://#',
info: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
}
]
},
{
id: 2,
category: 'Category2',
items: [{
id: 1,
name: 'Link1',
url: 'https://#',
info: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
}]
},
{
id: 3,
category: 'Category3',
items: [{
id: 1,
name: 'Link1',
url: 'https://#',
info: ''
}]
}
]
Vue.component('link-component', {
template: `
<div>
<h4>Links</h4>
<!-- Search -->
<input type="text" v-model="search" append-icon="search" placeholder="Search"></input>
<!-- Level 1 -->
<div v-for="value in filteredLinks" :key="value.id">
<pre>{{ value.category }}</pre>
</div>
<!-- Level 2 -->
<div class="card-content" v-for="item in value.items" :key="item.id">
<p>
<a :href="item.url" target="_blank">{{ item.name }}</a>
</p>
<p> {{ item.info }} </p>
</div>
</div>
`,
data: {
links,
search: ''
},
computed: {
filteredLinks () {
return this.links.filter(links => {
return links.items.toLowerCase().includes(this.search.toLowerCase())
})
}
}
});
new Vue({
el: '#app'
});
I think this is really simple but I don't get it running... Can someone help? Thanks!
I import the links from a json file and figured out to filter them like this:
filteredLinks () {
return this.links.filter((link) => {
return link.items.some((item) => {
return item.name.toLowerCase().includes(this.searchQuery.toLowerCase())
})
})
}
Related
Using Gatsbyjs and GrapghQL queries don't work on the site. They work in the testing environment.
import React from "react";
import { Link, graphql, useStaticQuery } from "gatsby";
import Img from "gatsby-image";
import PropTypes from "prop-types";
// Components
import Layout from "../components/layout";
// CSS
import "../css/index.css";
// Page
const Index = () => {
return (
<Layout>
{/* Hero */}
<section id="hero">
<div className="hero-title container">
<h1>Web design and development</h1>
<h2>Costume Solutions for companies and individuals</h2>
</div>
</section>
{/* Services */}
<section id="services">
<div className="title">
<h2>Our Services</h2>
<h3>We Provide You Quality</h3>
</div>
<div className="services container">
<div className="service web-design">
<h2>Web Design</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
</div>
<div className="service social-media">
<h2>Social Media</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
</div>
<div className="service video-production">
<h2>Video Production</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
</div>
</div>
</section>
{/* portfolio */}
<section id="Portfolio">
<div className="title">
<h2>Portfolio</h2>
<h3>Some Of Our Awesome Projects</h3>
</div>
<div className="portfolio container"></div>
</section>
</Layout>
);
};
// Index.propTypes = {
// data: PropTypes.object.isrequired,
// };
export const query = graphql`
{
protfolioImages: allFile(
filter: { relativeDirectory: { eq: "portfolio" } }
) {
nodes {
id
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
`;
export default Index;
ERROR:
Multiple "root" queries found in file: "cUsersAndreDocumentsProgramingjarboeStudiossrcpagesindexJsx2863101410" and "cUsersAndreDocumentsProgramingjarboeStudiossrcpagesindexJsx2863101410".
Only the first ("cUsersAndreDocumentsProgramingjarboeStudiossrcpagesindexJsx2863101410") will be registered.
Instead of:
1 | query cUsersAndreDocumentsProgramingjarboeStudiossrcpagesindexJsx2863101410 {
2 | bar {
3 | #...
4 | }
5 | }
6 |
7 | query cUsersAndreDocumentsProgramingjarboeStudiossrcpagesindexJsx2863101410 {
8 | foo {
9 | #...
10 | }
11 | }
Do:
1 | query cUsersAndreDocumentsProgramingjarboeStudiossrcpagesindexJsx2863101410AndCUsersAndreDocumentsProgramingjarboeStudiossrcpagesindexJsx2863101410 {
2 | bar {
3 | #...
4 | }
5 | foo {
6 | #...
7 | }
8 | }
Looking into this it seems like other users have experienced this problem and have come up with two possible causes and solutions.
It may be related to your CMD. Apparently running Gatsby Build from Windows terminal produces the 'Multiple root queries' error, while running the same command with git bash compiles successfully.
Or Having multiple graphql queries on the same page, in this case separating the queries into their own files and importing them back again fixes the problem.
Have been searching for a while. I am using Gatsby and I have no errors in the console or terminal but values are undefined. Could it be because of the second "data" under "articles"?
GraphiQL Query:
Query/Component Code:
import React, { Component } from 'react'
import { graphql } from 'gatsby'
// This query is executed at build time by Gatsby.
export const GatsbyQuery = graphql`
{
umdHub {
articles {
data {
title
}
}
}
}
`
class ClientFetchingExample extends Component {
render() {
const {
umdHub: { articles },
} = this.props.data
console.log(articles.title)
return (
<div style={{ textAlign: 'center', width: '600px', margin: '50px auto' }}>
<h1>{articles.title} - Is the title of the article</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
)
}
}
export default ClientFetchingExample
You already halfway there just small changes
const {
umdHub: { articles },
} = this.props.data
Now you have this articles object like this
articles: {
data: [
{
title: 'Learning to Listen'
},
{
title: 'Second Title'
}
...
]
}
Now you need to loop over data
import _ from 'lodash'
const data = _.get(articles, 'data', [])
_.map(data, title => {
console.log({ title })
})
If you want to only first title then
const title = _.get(articles, 'data[0].title', 'default value or blank string')
Here lodash is A modern JavaScript utility library delivering modularity, performance & extras.
I am trying to implement search/filter in my react project but can't seem to get it right.
Screenshot
This is what the user should be able to do:
Filter by text
Filter by location using the checkbox
or filter by job category
What I have right now is that I can filter by both text and checkbox, but I want the user to be able to search by text, e.g., "Dallas", "information technology", "sales" and then filter further by category or by location using the returned data from the text search.
This is my set up:
Searching by text uses a reducer to filter the array by search text
Checking a location or category checkbox stores the value in the category or keyword array
In the combine reducer file, I filter the jobs array in the store and memorize it using reselect.
I have a couple of glitches with the search text and checkbox functionalities. The filter by location checkbox functionality works fine by itself; however, when a checkbox is selected, and I enter search text, checkbox gets deselected. I want the checkbox to be still checked and displayed in the window when text is entered in the input field.
I'm a newbie, any help, suggestions, or a better approach to this functionality will be greatly appreciated.
SEARCHFORM.JS:
import React, {Component} from 'react';
//import {FormGroup, FormControl, InputGroup} from 'react-bootstrap';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { searchJobs, getJobs } from '../actions/jobaction';
import {selectKeywordCity,deselectKeywordCity} from '../actions/selectDeselectCityAction';
import {selectKeywordCategory,deselectKeywordCategory} from '../actions/selectDeselectCategoryAction';
class Search extends Component{
constructor(props){
super();
this.state = {
keyword:'',
checked:[]
};
this.handleChk = this.handleChk.bind(this);
}
handleInput = (event) => {
this.setState({
keyword: event.target.value
});
this.props.searchJobs(this.state.keyword);
}
/* handleSearch = (event) => {
event.preventDefault();
this.props.getJobs(this.state.keyword);
} */
clearForm = () => {
this.inputSearch.value = "";
this.setState({
keyword: this.inputSearch.value
});
this.props.getJobs();
}
handleChk = (e, keyword, type) => {
if(type==='city'){
e.target.checked ? this.props.selectKeywordCity(keyword) : this.props.deselectKeywordCity(keyword);
}else if(type==='category'){
e.target.checked ? this.props.selectKeywordCategory(keyword) : this.props.deselectKeywordCategory(keyword);
}
}
//Render Cities
renderCities(data){
if(data){
const cities = Object.keys(data).map(el => {
return data[el].city
}).sort()
.reduce((city,name) => {
const cityCount = city[name] ? city[name] + 1 : 1;
return{
...city, [name]:cityCount,
};
},{});
return Object.keys(cities).map((keyname, index) => {
return (
<li key={keyname}>
<input type="checkbox"
onChange={e=>this.handleChk(e,keyname,'city')}
className="chkbox"
/>
{keyname}
<span className="pull-right">{cities[keyname]}</span>
</li>)
})
}else{
return("nada")
}
}
//Render Job Categories
renderCategories(data){
if(data){
const categories = Object.keys(data).map(el => {
return data[el].category
}).sort()
.reduce((category,name) => {
const categoryCount = category[name] ? category[name] + 1 : 1;
return{
...category, [name]:categoryCount,
};
},{});
return Object.keys(categories).map((keyname, index) => {
return (
<li key={keyname}>
<input type="checkbox"
onChange={e=>this.handleChk(e,keyname,'category')}
className="chkbox"
/>
{keyname}
<span className="pull-right">{categories[keyname]}</span>
</li>)
})
}else{
return("nada")
}
}
render(){
let closeBtn = null;
if(this.state.keyword){
closeBtn = (<i className="fa fa-times" onClick={this.clearForm}></i>);
}
return(
<div>
<div className="side-search">
<i className="fa fa-search"></i>
<input type="text"
placeholder="Keyword Search"
ref={el => this.inputSearch = el}
onChange={this.handleInput}
value={this.state.keyword}
/>
{closeBtn}
</div>
<div className="chk_boxes">
<h4>Location</h4>
<ul>
{
this.renderCities(this.props.jobs)
}
</ul>
</div>
<div className="chk_boxes">
<h4>Category</h4>
<ul>
{
this.renderCategories(this.props.jobs)
}
</ul>
</div>
</div>
)
}
}
function mapStateToProps(state){
return{
jobs: state.jobs.jobs
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({searchJobs,
getJobs,
selectKeywordCity,
deselectKeywordCity,
selectKeywordCategory,
deselectKeywordCategory},
dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(Search);
JOBACTION:
import axios from 'axios';
const FETCH_URL = 'http://localhost:3006';
/* GET ALL JOB LISTINGS */
export function getJobs(){
return function(dispatch){
axios.get(`${FETCH_URL}/jobs`)
.then(function(response){
dispatch({type:'GET_JOBS',payload:response.data})
}).catch(function(err){
dispatch({type:'GET_JOBS_ERROR', payload:err});
})
}
}
/* GET ALL JOB LISTINGS */
export function searchJobs(keyword){
return function(dispatch){
axios.get(`${FETCH_URL}/jobs?q=${keyword}`)
.then(function(response){
dispatch({type:'SEARCH_JOBS',payload:response.data})
}).catch(function(err){
dispatch({type:'SEARCH_JOBS_ERROR', payload:err});
})
}
}
JOBSLIST REDUCER:
export function Listings (state={}, action){
switch(action.type){
case 'GET_JOBS':
return{...state, jobs:action.payload}
case 'SEARCH_JOBS':
return{...state, jobs:action.payload}
default:
return state;
}
}
SELECTDESELECT(CHECKBOX) REDUCER:
const INITIAL_STATE = {
keywords:[]
}
export function filterCity(state=INITIAL_STATE, action){
switch(action.type){
case 'SELECT_CITY':
return{
keywords:[...state.keywords, action.payload]
}
case 'DESELECT_CITY':
const currentKeywordToDelete = [...state.keywords];
const indexOfKeyword = currentKeywordToDelete.findIndex(function(keyword){
return keyword === action.payload
});
return{
keywords:[...state.keywords.slice(0,indexOfKeyword), ...currentKeywordToDelete.slice(indexOfKeyword+1) ]
}
default:
return state;
}
}
COMBINEREDUCER:
import {combineReducers} from 'redux';
import {createSelector} from 'reselect';
import {Listings} from './listingsReducer';
import {filterCity} from './select-deselect-city';
import {filterCategory} from './select-deselect-category';
const reducer = combineReducers({
jobs: Listings,
keywords: filterCity,
category: filterCategory
});
export const selectJobList = (state) => state.jobs.jobs;
export const selectCities = (state) => state.keywords.keywords;
//export const selectCategories = (state) => state.categories.categories;
export const selectFilteredJobs = createSelector(
selectJobList,selectCities,
(jobs,cities) => {
if(cities && cities.length > 0){
const filteredData = Object.keys(jobs)
.filter(key => cities.includes(jobs[key].city))
.reduce((obj, key) => {
return [...obj, {...jobs[key]}]
}, []);
//console.log(filteredData);
return filteredData;
}else{
return jobs
}
}
)
export default reducer;
JSON DATA:
{
"jobs": [
{
"id": 1,
"title": "Financial Analyst II",
"description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. .",
"category": "Sales",
"dept": "Finance",
"date": "07/11/2018",
"experience": ["Bachelors Degree","Five years of sales experience"],
"city": "Dallas",
"state":"Texas",
"salary": "10,000"
},
{
"id": 2,
"title": "Application Support Speacialist",
"description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.",
"category": "Information Technology",
"dept": "Accounting",
"date": "07/10/2018",
"experience": ["Bachelors Degree","Two years of sales experience"],
"city": "Dallas",
"state":"Texas",
"salary": "20,000"
}
}
I'm trying to get a list of news and then render them in the template of my component.
I was learning from this tutorial, which is a little bit out of date, http://chariotsolutions.com/blog/post/angular2-observables-http-separating-services-components/
The news item class looks like this
export class NewsItemComponent {
text: string;
date: Date;
author: string;
link: string
constructor(text: string,
date: Date,
author: string,
link: string) {
this.text = text;
this.date = date;
this.author = author;
this.link = link;
}
}
The service retrieving the data:
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { NewsItemComponent } from './news-item/news-item.component';
#Injectable()
export class NewsService {
constructor(public http: Http) {
console.log('Creating NewsService');
}
getNews() {
let url = 'http://localhost/test-api/';
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
this.http.post(url, '', options)
// initial transform - result to json
.subscribe( (res:Response) => {
let articles: Array<any> = [];
res.json().map((articles: Array<any>) => {
articles.push(new NewsItemComponent('asd', new Date(), 'asdf', 'asdf'));
});
console.log('articles', articles);
return articles
});
}
}
The main component:
import { Component, OnInit, AfterViewInit, AfterViewChecked } from '#angular/core';
import { Http, Response, RequestOptions, Headers, Request, RequestMethod } from '#angular/http';
import { TranslateService } from 'ng2-translate/ng2-translate';
import { NewsItemComponent } from './news-item/news-item.component';
import { NewsService } from './news-service.service';
#Component({
selector: 'news-section',
templateUrl: './news-section.component.html',
styleUrls: ['./news-section.component.scss'],
providers: [ NewsService ]
})
export class NewsSectionComponent implements AfterViewInit {
articles: NewsItemComponent[];
constructor(translate: TranslateService, private http: Http, public newsService: NewsService) {
translate.setDefaultLang('en');
translate.use('en');
this.articles = [];
newsService.getNews().subscribe(res => this.articles = res);
}
}
And the view:
<section id="news" sectionVisible>
<div>
<h1>{{ 'Nav.News' | translate }}</h1>
</div>
<div class="news-wrapper clear-fix">
<div class="column carousel-cell" ngFor="#article of articles">
<article>
<a href="#" class="hovered">
<div class="bg-hover">
<p>
Visit
</p>
</div>
</a>
<h2>News title</h2>
<time>21.10.2015 16:30</time>
<p>
Etiam faucibus sodales leo, rutrum molestie nisi luctus in. Duis quis viverra diam, vitae hendrerit augue. Donec ultricies nisi vel placerat sodales. Donec varius convallis mauris egestas vulputate. Integer fermentum tincidunt hendrerit. Donec eget nisl
eros. Pellentesque a fringilla lorem.
</p>
</article>
</div>
</div>
</section>
Of course in the view the lorem ipsum parts will be changed by the data retrieved. But there is something wrong with the service:
newsService.getNews().subscribe(res => this.articles = res);
this line raises an error:
Property subscribe does not exist on type void
And I have no idea why it is caused.
Any hints?
You need to remove the subscribe method from your service. Services should only return the Observables, subscribing should be done in the actual component.
Subscribing to an Observable is equal to calling a function. You want to retrieve the result in your component, so that's where you need to subscribe. The service should only hold the logic to prepare the data after the HTTP call (calling for example res.json()).
Service
getNews() {
let url = 'http://localhost/test-api/';
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(url, '', options)
.map(res => res.json());
}
Component:
newsService.getNews()
.subscribe( news => {
let articles: Array<any> = [];
news.map((articles: Array<any>) => {
articles.push(new NewsItemComponent('asd', new Date(), 'asdf', 'asdf'));
});
this.articles = articles
});
I am trying to use the YUI datatable to display data from a JSON object which looks like this:
{"results":[{"label":"Column 1","notes":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "},{"label":"Column 2","notes":"Lorem ipsum dolor sit amet, consectetur adipiscing elit."},{"label":"Column 3","notes":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "},{"label":"Column 4","notes":"Lorem ipsum dolor sit amet, consectetur adipiscing elit."},{"label":"Column 5","notes":"Lorem ipsum dolor sit amet, consectetur adipiscing elit."},{"label":"Column 6","notes":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "}]}
I can do this fine with the standard implementation. However, the column names (labels in above object) are dynamic so I will not know them until the data reaches the page. I therefore want to define the column definitions from the datasource which I am doing in doBeforeParseData().
From reading / IRC, it has been suggested that I should be able to add columns to the data table. I want the table to look like this:
Column 1 Column 2.......
note note.....
so the above data should produce one row of data. Here's what I have so far:
function loadTable() {
YAHOO.example.Basic = function() {
var myColumnDefs = [];
var myDataSource = new YAHOO.util.DataSource("/index/testajax");
myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
myDataSource.doBeforeParseData = function (oRequest, oFullResponse, oCallback) {
// alert(oFullResponse);
var colDefs = [];
var len = oFullResponse.results.length;
for (var i = 0; i < len; i++) {
var obj = {
key: oFullResponse.results[i].label,
sortable: true,
resizeable: true
};
myColumnDefs.push(obj);
}
console.log(myColumnDefs);
return oFullResponse;
};
myDataSource.responseSchema = {
resultsList:"results",
fields: ["label","notes"]
};
var myDataTable = new YAHOO.widget.DataTable("json",
myColumnDefs, myDataSource, {caption:"DataTable Caption"});
return {
oDS: myDataSource,
oDT: myDataTable
};
}();
}
Would be grateful for on any input on HOW to do this rather than why I shouldn't ;-)
thanks,
codecowboy
I spent a bit of my lunch hour on this, but I got something working for you. I looked at your JSON and the way you did it would not work in the data table. results is a list, every entry is a row, and every attribute is a column. Here is the json that I came up with that I hope works for you.
{
"resultSet":{
"columnList":[
{"key":"Column1","label":"My Col 1"},
{"key":"Column2","label":"My Col 2"},
{"key":"Column3","label":"My Col 3"}
],
"results":[
{
"Column1":"Row 1 value",
"Column2":"Row 1 value",
"Column3":"Row 1 value"
},
{
"Column1":"Row 2 value",
"Column2":"Row 2 value",
"Column3":"Row 2 value"
}
]
}
}
I made a small javascript object for handling what you need to do. What needs to be done is you need to make an ajax call to the server for the data. This is so you can define the columns in the datasource before you MAKE the datasource.
function DataProvider(url){
this.url = url;
}
DataProvider.prototype = {
url:null,
data:null,
ds:null,
getData:function() {return this.data},
initialize:function(){
YAHOO.util.Connect.asyncRequest('GET', this.url, this);
},
success:function(response){
var responseVal = YAHOO.lang.JSON.parse(response.responseText);
var columnList = responseVal.resultSet.columnList;
this.data = responseVal.resultSet.results;
this.ds = new YAHOO.util.FunctionDataSource(function(){return this.dataProvider.getData()});
this.ds.responseSchema = {
resultsList:"resultSet.results",
fields:columnList
}
this.ds.dataProvider = this;
/* make call to initialize your table using the data set */
var myDataTable = new YAHOO.widget.DataTable("basic", columnList, this.ds, {caption:"DataTable Caption"});
//console.debug(columnList);
//console.debug(this.data);
}
}
So when the page loads do the following
function init(){
var dataProvider = new DataProvider('testjson.json');
dataProvider.initialize();
}
And your html should look like this
<body onload="init()" class="yui-skin-sam">
<div id="basic"></div>
</body>
And you should have the following scripts included
<!-- css -->
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.7.0/build/datatable/assets/skins/sam/datatable.css">
<!-- js -->
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/connection/connection-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/datasource/datasource-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/element/element-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/datatable/datatable-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/json/json-min.js"></script>
That should work, works for me in both IE and firefox.