I try to iterate through a Django Rest API object list using VueJS. I can get the articles json list but I can't correctly view VueJs template component. In my Django views I use
<section class="blog-post-wrap medium-padding80">
<div class="container">
<div class="row">
<div id="starting">
<div class="" v-for="article in articles">
<articlelist title="article.title"></articlelist>
</div>
</div>
</div>
</div>
</section>
And I use VueJs component template
Vue.component('articlelist', {
template: `
<div class="col col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12">
<div class="ui-block"
<div class="post-content">
THE COMMUNITY
{{title}}!
<p>Here’s a photo from last month’s photoshoot. We got really awesome shots for the new catalog.</p>
</div>
<!-- ... end Post -->
</div>
</div>
`,
props: ['title']
});
new Vue({
el: '#starting',
delimiters: ['${','}'],
components:{
'articlelist': articlelist,
},
data: {
articles: [],
loading: false,
currentArticle: {},
message: null,
newArticle: {
'title': null,
'content': null,
},
},
mounted: function() {
this.getArticles();
},
methods: {
getArticles: function() {
this.loading = true;
this.$http.get('/api/articles/')
.then((response) => {
this.articles = response.data;
console.log(response.data);
this.loading = false;
})
.catch((err) => {
this.loading = false;
console.log(err);
})
},
getArticle: function(id) {
this.loading = true;
this.$http.get(`/api/articles/${id}/`)
.then((response) => {
this.currentArticle = response.data;
this.loading = false;
})
.catch((err) => {
this.loading = false;
console.log(err);
})
},
addArticle: function() {
this.loading = true;
this.$http.post(`/api/articles/`,this.newArticle)
.then((response) => {
this.loading = false;
this.getArticles();
})
.catch((err) => {
this.loading = false;
console.log(err);
})
},
updateArticle: function() {
this.loading = true;
this.$http.put(`/api/articles/${this.currentArticle.article_id}/`, this.currentArticle)
.then((response) => {
this.loading = false;
this.currentArticle = response.data;
this.getArticles();
})
.catch((err) => {
this.loading = false;
console.log(err);
})
},
deleteArticle: function(id) {
this.loading = true;
this.$http.delete(`/api/articles/${id}/` )
.then((response) => {
this.loading = false;
this.getArticles();
})
.catch((err) => {
this.loading = false;
console.log(err);
})
}
}
});
I am aware that I could not manage to correct the naming of components and scripts but I can not find the correct way.
When I check chrome dev tools, I see error :
Uncaught ReferenceError: articlelist is not defined
Can you help me ?
Thanks
Related
If i use getcoords() , returns always just the first latitude and longitude for all my array length.
If i use normal syntax {{fire.latitude}},{{fire.longitude}} returns all latitudes and longitudes.
i don't know why, probably a very simple thing
this is the first problem that write, i hope to be was clear.
thanck all for the help .
<template>
<div>
<div v-for="(fire, index) in fires" :key="index">
<!-- {{index}}.{{getCoords()}} -->
{{fire.lat}},{{fire.lon}}
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'FiresList',
data () {
return {
fires: null,
errored: false,
}
},
mounted () {
axios.get('https://storage.googleapis.com/public.storykube.com/start2impact/fires.json')
.then(response => {
this.fires = response.data.map((coords)=> {
return {lat: coords.latitude, lon: coords.longitude, date: coords.date}
})
console.log(this.fires);
})
.catch(error => {
console.log(error)
this.errored = true
})
},
methods: {
getCoords (){
for (var latlon in this.fires){
return [this.fires[latlon].lat, this.fires[latlon].lon]
//OTHERWISE
// for (let i = 0; i <= this.fires.length; i++){
// return [this.fires[i].lat, this.fires[i].lon]
}
}
}
}
</script>
<style scoped>
</style>
I think what you are looking for is this:
<div v-for="(fire, index) in fires" :key="index">
{{index}}.{{getCoords(index)}}
</div>
getCoords(index) {
return [this.fires[index].lat, this.fires[index].lon]
}
I have a problem. I want to create instant search, without any search button, that when i'm typing e.g. more than 3 letters, my results will be instant show below.
My code:
<template>
<div class="nav-scroller py-1 mb-2">
<div class="nav d-flex justify-content-between">
<input v-model="keyword" class="form-control" type="text" placeholder="Search" aria-label="Search">
<div v-bind:key="result.id" v-for="result in results">
<p>Results are: {{ result.title }}</p>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Home',
components: {
},
data() {
return {
keyword: '',
results: [],
}
},
methods: {
getResults() {
axios.get("http://127.0.0.1:8000/api/v1/books/?search="+this.keyword)
.then(res => (this.results = res.data))
.catch(err => console.log(err));
}
},
created() {
this.getResults()
}
}
</script>
Now my 'keyword' parameter is probably not passed to the url, because when I refresh the page, all records from APi are the results.
Could you help me?
You should either call method when input changes
<input v-model="keyword" #input="getResults">
and method:
getResults() {
if (this.keyword.length > 3)
axios.get("http://127.0.0.1:8000/api/v1/books/?search="+this.keyword)
.then(res => (this.results = res.data))
.catch(err => console.log(err));
}
}
Or watcher can be used. When keyword changes watcher will call getResults method.
watch: {
keyword: "getResults"
}
Use watcher for the keyword value update.
Whenever keyword is more than 3 letters, request the getResults() method to search.
export default {
name: 'Home',
components: {
},
data() {
return {
keyword: '',
results: [],
}
},
watch: {
keyword: function(newVal) {
if (newVal.length >2) {
this.getResults();
}
}
},
methods: {
getResults() {
axios.get("http://127.0.0.1:8000/api/v1/books/?search="+this.keyword)
.then(res => (this.results = res.data))
.catch(err => console.log(err));
}
},
created() {
this.getResults()
}
}
I have a component that I want to test that uses Vuex.
components/Main/Header.vue
<template>
<v-container fluid grid-list-xl>
<v-card flat class="header" color="transparent">
<v-layout align-center justify-start row fill-height class="content">
<v-flex xs5>
<v-img :src="avatar" class="avatar" aspect-ratio="1" contain></v-img>
</v-flex>
<v-flex xs7>
<div class="main-text font-weight-black">
WELCOME
</div>
<div class="sub-text">
{{currentLocation.description}}
</div>
<div #click="showStory" class="show-more font-weight-bold">
Explore More
</div>
</v-flex>
</v-layout>
</v-card>
</v-container>
</template>
<script>
import avatar from '../../assets/images/home/avatar.png';
export default {
name: 'Header',
computed: {
currentLocation() {
return this.$store.getters.getCurrentLocation;
},
avatar() {
return avatar;
}
},
methods: {
showStory() {
this.$router.push( { name: 'Stories', params: { name: 'Our Story' } });
}
}
}
</script>
and from /test/unit/components/Main/Header.spec.js
import Vuex from 'vuex'
import { shallowMount, createLocalVue } from "#vue/test-utils"
import Header from "#/components/Main/Header.vue"
const localVue = createLocalVue()
localVue.use(Vuex)
const store = new Vuex.Store({
state: {
currentLocation: {
name: 'this is a name',
description: "lorem ipsum",
latitude: '1.123123',
longitude: '103.123123',
radius: '5000'
}
},
getters: {
getCurrentLocation: (state) => state.currentLocation
}
})
describe('Header', () => {
const wrapper = shallowMount(Header, {
store,
localVue
})
it('should render a computed property currentLocation', () => {
expect(Header.computed.currentLocation()).toBe(store.getters.getCurrentLocation)
});
});
The error I'm getting is from the computed property currentLocation
TypeError: Cannot read property 'getters' of undefined
I am new to react. I am following https://www.truecodex.com/course/react-js this example but in this example, it shows all the customers. I want to add a dropdown with no. of pages and on-page selection changes the values in the table.
I think, I should take one more customer{} and add 1-4customer 2-next4customer and then on dropdown selection on change change the table values
Here is my Customer view class where I am fetching all customers.
import React from 'react';
import { Table,Icon, Button } from 'semantic-ui-react';
export default class CustomerView extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
deleteTitle: "customer",
isLoaded: false,
formClose: false,
singleCustomer: [],
users: []
}
}
//fetch data
componentDidMount() {
const customerApi = 'https://localhost:44387/api/Customers';
const myHeader = new Headers();
myHeader.append('Content-type', 'application/json');
myHeader.append('Accept', 'application/json');
myHeader.append('Origin', 'https://localhost:44387');
const options = {
method: 'GET',
myHeader
};
fetch(customerApi, options)
.then(res => res.json())
.then(
(result) => {
this.setState({
users: result,
isLoaded: true
});
},
(error) => {
this.setState({
isLoaded: false,
error
});
}
)
}
//Delete Customer
onDeleteCustomer = customerId => {
const { users } = this.state;
this.setState({
users: users.filter(customer => customer.customerId !== customerId)
});
const customerApi = 'https://localhost:44387/api/Customers/' + customerId;
const myHeader = new Headers({
'Accept': 'application/json',
'Content-type': 'application/json; charset=utf-8'
});
fetch(customerApi, {
method: 'DELETE',
headers: myHeader
})
.then(res => res.json())
.then(
(result) => {
this.setState({
})
}, (error) => {
this.setState({ error });
}
)
}
render() {
const { users } = this.state;
return (
<div>
<Button color='blue' onClick={() => this.props.onCreate()}>New Customer</Button>
<br/>
<br/>
<Table celled textAlign='center'>
<Table.Header>
<Table.Row>
<Table.HeaderCell>ID</Table.HeaderCell>
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>Address</Table.HeaderCell>
<Table.HeaderCell>Action</Table.HeaderCell>
<Table.HeaderCell>Action</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body >
{
users.map(user => (
<Table.Row key={user.customerId}>
<Table.Cell>{user.customerId}</Table.Cell>
<Table.Cell>{user.name}</Table.Cell>
<Table.Cell>{user.address}</Table.Cell>
<Table.Cell>
<Button color='yellow' icon labelPosition='right'
onClick={() => this.props.onEditCustomer(user.customerId)}>
<Icon name='edit outline'/>
Edit</Button>
</Table.Cell>
<Table.Cell>
<Button color='red' icon labelPosition='right'
onClick={() => this.props.onDeleteClick(user.customerId)}>
<Icon name='trash alternate'/>
Delete</Button>
</Table.Cell>
</Table.Row>
))
}
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.HeaderCell colSpan='5'>
No of Pages
</Table.HeaderCell>
</Table.Row>
</Table.Footer>
</Table>
</div>
)
}
}
I am using ReactJs and Mocha and trying few unit tests. I have two mandatory form fields First Name and Last Name. I am trying to test the validation where if only one field is entered, the other field displays the missing value validation error.
Below code simulates the changes to the value and simulates the form submit.
TestUtils.Simulate.change(firstNameElement , {target: {value: 'Joe'}});
TestUtils.Simulate.submit(formElement)
The changed value is reflected in the event handlers on First Name. But, not in the test. So, both the fields display missing value validation failing my test.
What I could be doing wrong here?
Below are code:
//NameForm.jsx
'use strict';
var React=require('react')
var forms = require('newforms')
var NameForm = forms.Form.extend({
firstName: forms.CharField({maxLength: 100, label: "First name(s)"}),
lastName: forms.CharField({maxLength: 100, label: "Last name"}),
cleanFirstName(callback) {
callback(null)
},
render() {
return this.boundFields().map(bf => {
return <div className={'form-group ' + bf.status()}>
<label className="form-label" htmlFor={bf.name}>
<span className="form-label-bold">{bf.label}</span>
</label>
{bf.errors().messages().map(message => <span className="error-message">{message}</span>)}
<input className="form-control" id={bf.name} type="text" name={bf.name} onChange = {this.onChangeHandler}/>
</div>
})
}
, onChangeHandler: function(e){
console.log("onchnage on input is called ----- >> " + e.target.value)
}
})
module.exports = {
NameForm
}
Here is NamePage.jsx:
'use strict';
var React = require('react')
var {ErrorObject} = require('newforms')
var superagent = require('superagent-ls')
var {API_URL} = require('../../constants')
var {NameForm} = require('./NameForm')
var NamePage = React.createClass({
contextTypes: {
router: React.PropTypes.func.isRequired
},
propTypes: {
data: React.PropTypes.object,
errors: React.PropTypes.object
},
statics: {
title: 'Name',
willTransitionTo(transition, params, query, cb, req) {
if (req.method != 'POST') { return cb() }
superagent.post(`${API_URL}/form/NameForm`).send(req.body).withCredentials().end((err, res) => {
if (err || res.serverError) {
return cb(err || new Error(`Server error: ${res.body}`))
}
if (res.clientError) {
transition.redirect('name', {}, {}, {
data: req.body,
errors: res.body
})
}
else {
transition.redirect('summary')
}
cb()
})
}
},
getInitialState() {
return {
client: false,
form: new NameForm({
onChange: this.forceUpdate.bind(this),
data: this.props.data,
errors: this._getErrorObject()
})
}
},
componentDidMount() {
this.setState({client: true})
},
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
var errorObject = this._getErrorObject(nextProps.errors)
this.refs.nameForm.getForm().setErrors(errorObject)
}
},
_getErrorObject(errors) {
if (!errors) { errors = this.props.errors }
return errors ? ErrorObject.fromJSON(errors) : null
},
_onSubmit(e) {
e.preventDefault()
var form = this.state.form
form.validate(this.refs.form, (err, isValid) => {
if (isValid) {
this.context.router.transitionTo('name', {}, {}, {
method: 'POST',
body: form.data
})
}
})
},
render() {
return <div>
<h1 className="heading-large">Your name</h1>
<form action='name' method="POST" onSubmit={this._onSubmit} ref="form" autoComplete="off" noValidate={this.state.client}>
{this.state.form.render()}
<button type="submit" className="button">Next</button>
</form>
</div>
},
})
module.exports = NamePage
Here is NameTest.js :
//NameTest.js
var React = require('react')
var ReactAddons = require('react/addons')
var TestUtils = React.addons.TestUtils
var InputFieldItem = require('../../src/page/name/NamePage')
describe('Name page component', function(){
var renderedComponent;
before('render element', function() {
console.log("*** in before")
renderedComponent = TestUtils.renderIntoDocument(
<InputFieldItem />
);
});
it('Only First Name entered should display one error message', function() {
renderedComponent = TestUtils.renderIntoDocument(
<InputFieldItem />
);
var formElement = TestUtils.findRenderedDOMComponentWithTag(renderedComponent, 'form').getDOMNode()
var firstNameElement = TestUtils.scryRenderedDOMComponentsWithTag(renderedComponent, 'input')[0].getDOMNode()
var lastNameElement = TestUtils.scryRenderedDOMComponentsWithTag(renderedComponent, 'input')[1].getDOMNode()
var buttonElement = TestUtils.findRenderedDOMComponentWithTag(renderedComponent, 'button').getDOMNode()
TestUtils.Simulate.change(firstNameElement , {target: {value: 'Joe'}});
TestUtils.Simulate.submit(formElement)
var errorSpans = TestUtils.scryRenderedDOMComponentsWithClass(renderedComponent, 'error-message')
console.log("First name value is :|"+ firstNameElement.value + "|")
expect (errorSpans.length).to.equal(1)
})
});