This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
While the VueJS data that is populated from Axios Get method and can be confirmed by outputting the data into console, I am not able to access the data from the front end.
Here is my sample JSON ouput
{
"locations" : {
"items" : ["abc","def","ghi"],
"selectedLocation" : ""
},
"categories" : {
"items" : {
"doctor" : ["test", "test2", "test3"],
"management" : ["test1","test2","test3"]
},
"subcategories":[],
"selectedCategory":"",
"selectedSubCategory":""
}
Here is my Front End Code
<form id="vueAppJobSearchPanel" class="offset-top-10 offset-sm-top-30" action="/job-search">
<div class="group-sm group-top">
<div style="max-width: 230px;" class="group-item element-fullwidth">
<div class="form-group">
<select v-model="locations.selectedLocation" id="form-filter-location" name="loc" data-minimum-results-for-search="Infinity" class="form-control">
<option value="">{{global.job_search_panel.placeholder_title_location}}</option>
<option v-for="location in locations.items" :value="location">${location}</option>
</select>
</div>
</div>
<div style="max-width: 230px;" class="group-item element-fullwidth">
<div class="form-group">
<select v-model="categories.selectedCategory" id="form-filter-location" name="cat" data-minimum-results-for-search="Infinity" class="form-control">
<option value="">{{global.job_search_panel.placeholder_title_category}}</option>
<option v-for="(category_obj, category) in categories.items" :value="category">${category}</option>
</select>
</div>
</div>
</div></form>
Here is my VueJS and AXIOS code
const vm = new Vue({
el: '#vueAppJobSearchPanel',
delimiters: ['${', '}'],
data: {
test: {
"items" : ["abc","def","ghi"],
"selectedLocation" : ""
},
locations : {},
categories : {}
},
mounted(){
this.loadDropDown();
},
methods: {
loadDropDown : function() {
let modelName = "CustomModule1";
let apiUrl = '/api/' + modelName + '/getFields';
axios.get(apiUrl)
.then(function (response) {
this.locations = constructLocationDropDownValues(response, modelName);
this.categories = constructCategorySubCategoryDropDownValues(response, modelName);
})
.catch(function (error) {
console.log(error);
});
}
}});
this.locations inside the loadDropDown function return a valid JSON. However the JSON is not passed to the front end (i.e. HTML). When I tried to output "locations" it will return an empty {}
Ideas? Thank you
The problem is with 'this' inside the axios callback. You should use arrow function to keep the context
axios
.get(apiUrl)
.then(response => {
this.locations = constructLocationDropDownValues(response, modelName)
this.categories = constructCategorySubCategoryDropDownValues(response,modelName)
})
.catch(function (error) {
console.log(error)
})
Related
The issue I have occurs when a user enters a category. Categories like electronics, toys, and cars are written using v-if condition. So while we enter these three categories in the category field I don't want to show the radio button checked.
Here I have tried this by using like v-if="(category != 'Electronics')||(category != 'Toys')||(category != 'cars')" this condition but here this "||" condition is not working.
*input field for entering a category*
<div><input type="text" v-model="category" placeholder="Search your category"></div>
<div v-if="(category != 'Electronics')||(category != 'Toys')||(category != 'cars')">
<h1>Consumer</h1>
<div class="radio_select">
<input type="radio" v-model="picked" value="consumer">
<label>Personal Ad:</label>
<p>Personal ads can be posted one ad per month, which will appear with "sale by owner tag"</p><br>
<div>
<input type="radio" id="business" name="flag" value="business" v-model="picked">
<label>Business Ad:</label>
<p>Do you want to upgrade to business account to post more <br>ads per month</p>
<span class="prev_next">
<button class="prev_next_btn" #click.prevent="prev()">Previous</button>
<button class="prev_next_btn" #click.prevent="next()">Next</button>
</span>
</div>
</div>
</div>
vue.js
<script>
Vue.use(VueFormWizard)
new Vue({
el: '#q-vikreya',
components: {
"vue-form-g": VueFormGenerator.component
},
data() {
return {
step:1,
category:'',
model:'',
formOptions: {
validateAfterLoad: true,
validateAfterChanged: true
}
};
},
<!--/ By using this delimiters we were able to fix the vue.js compatibility with django. since the curly braces between django and-->
<!-- // vue.js conflicted, delimiters helped here to solve the conflicts-->
delimiters: ["<%","%>"],
ready: function() {
console.log('ready');
},
methods: {
prev(currentStep) {
if(this.checkForm()) {
if (currentStep === 4) {
this.step = 3
} else {
this.step--;
}
}
},
next(currentStep) {
if(this.checkForm()) {
if (currentStep === 4) {
this.step = 5
} else {
this.step++;
}
}
},
checkForm: function (e) {
if (this.category && this.title) {
return true;
}
this.errors = [];
if (!this.category) {
this.errors.push('Name required.');
}
if (!this.title) {
this.errors.push('Age required.');
}
e.preventDefault();
},
submitForm: function(){
axios({
method : "POST",
url: "{% url 'PostAd' %}", //django path name
headers: {'X-CSRFTOKEN': '{{ csrf_token }}', 'Content-Type': 'application/json'},
data : {"category":this.category, "title":this.title,
"address":this.address,
"city": this.city,
"state": this.state,
"zip": this.zip,
"price": this.price,
"description": this.description,
"radio_price": this.radio_price,
"Job_title": this.model,
},//data
}).then(response => {
console.log("response");
console.log(response.data);
this.success_msg = response.data['msg'];
window.location.replace('{% url "classifieds" %}') // Replace home by the name of your home view
}).catch(err => {
this.err_msg = err.response.data['err'];
console.log("response1");
console.log(err.response.data);
});
},
},
})
</script>
I am new to Vue.js, and I want to add a search function for my site. The data is from an API Call and is displayed using vue.js too.
Display HTML Code:
<div class="row" v-for="items in data">
<div class="col-lg-4 col-md-6" data-toggle="modal" data-target="#exampleModal" user="'items'" #click="sendInfo(items)">
<a href="#" class="latest-product__item">
<div class="latest-product__item__pic">
<img src="img/item_image_placeholder.jpg" alt="">
</div>
<div class="latest-product__item__text">
<h6>{{items.item_name}}</h6>
<div v-for="variant in items.variants">
<div v-for="store in variant.stores">
<span>{{store.default_price}}</span>
</div>
</div>
</div>
</a>
</div>
And here's my Vue.js:
window.onload = function () {
const access_token = "";
new Vue({
el: '#item-data',
data () {
return {
data:[],
selectedUser:'',
itemCart: [],
search:'',
quantity: '',
cartCheckout: []
}
},
mounted () {
axios.get('**api call here**', {
headers : {
Authorization: 'Bearer ' + access_token
},
params: {
limit: 250
}
})
.then((response) => {
// handle success
this.data = response.data.items
console.log(response);
removeLoader();
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
});
},
computed:{
cartItem(){
return store.getters.printCart;
},
count(){
return store.state.cartCount;
},
},
methods:{
sendInfo(items) {
this.selectedUser = items;
},
addCart: function(cartdets){
store.commit('addCart', cartdets);
store.commit('addCount', 1);
}
}
})
}
What I want now is to add a search function to my displayed items. I already added v-model to my input tag. The items are dynamically displayed using vue and I want a search function for specific items.
You could create a computed property, maybe name it something like filteredItems, and make it loop through all of your items and save the items you want to display into an array and then return that array.
Then in your html use a v-for to display the items from filteredItems.
I'm trying to fetch key "name" and its corresponding value using JSON in the drop down "Select" of reactJS. But it does not work when I'm executing my code. I have attached my code, Kindly have a look!
I have tried using componentDidMount to fetch the data by making API call. I am a beginner so I'm trying to figure out what ways can make it work.
class devName extends Component {
state = {
names: [],
selectedName: "",
validationError: ""
}
componentDidMount() {
fetch("http://127.0.0.1:8080/dashboard/get_names")
.then((res) => {
return res.json();
})
.then(data => {
let namesFromAPI = data.map(name => { return { value: name, display: name } })
this.setState({ names: [{ value: '', display: '(Select the site)' }].concat(namesFromAPI) });
}).catch(err => {
console.log(err);
});
}
render() {
return (
<div className="wrapper">
<div className="form-wrapper">
<Toolbar />
<form className="form">
<label className="label1">Select Name from the drop down</label> <hr />
<div>
<Select
value={this.state.selectedName}
onChange={(e) => this.setState({selectedName: e.target.value, validationError: e.target.value === "" ? "You must select a site name" : ""})}>
{/* placeholder="Loading Site List..." > */}
{this.state.names.map((name) => <option key={name.value} value={name.display}>{name.display} </option>)}
</Select>
<div style={{color: 'red', marginTop: '5px'}}>
{this.state.validationError}
</div>
<br />
</div>
<label className="label1">Create New Name From Template</label>
<hr />
<div className="addButton">
<button type="Submit">Add</button> <hr />
</div>
<div className="submitButton">
<button type="submit">Submit</button>
</div>
</form>
</div>
</div>
);
}
}
export default devName;
JSON CODE LOOKS LIKE:
[
{
"type": "state",
"id": 2131,
"temporaryEle": {},
"name": "First Unit#1234 TON" .. and so on
}
]
There is no error message. Though the desired result should be "Select Drop Down populates with : " Select one of the name please"
First Unit#1234 TON
Second Unit#8934 QON
Third Unit#6534 JON
Edit:
I've read one of your comments and it seems like you're having CORS issues with fetch.
Add the baseurl as proxy in your package.json file
// Package.json
{
...other configs,
"proxy": "http://127.0.0.1:8080"
}
Then you'd call your fetch like so: fetch('/dashboard/get_names').then((res) => {...})
Resource for you to look at:
https://create-react-app.dev/docs/proxying-api-requests-in-development/
Old:
According to your JSON data, you might have to destucture a level deeper on your object while mapping the data in componentDidMount
let namesFromAPI = data.map(({name}) => {
return { value: name, display: name }
})
// OR
let namesFromAPI = data.map(name => {
return { value: name.name, display: name.name }
})
Use destucturing on name parameter, you can implicitly return object from arrow function when you wrap it in () data.map(({name}) => ({ value: name, display: name }))
I have a ReactJS page with three dropdown list, two of the dropdown list are displaying duplicate values. The values are being consumed from a json file. I researched using filter to remove the duplicates, but I'm unsure as to how I'm to apply it to my array when using React JS along with Fetch.
I created a function which employs the filter method, but I'm uncertain as to how I'm to implement it onto data: [], which contains the data consumed from the json file. This is the sample json file: https://api.myjson.com/bins/b1i6q
This is my code:
import React, { Component } from "react";
class Ast extends Component {
constructor() {
super();
this.state = {
data: [],
cfmRateFactor: "10"
};
} //end constructor
change = e => {
this.setState({
[e.target.name]: e.target.value
});
}; //end change
removeDups(array) {
return array.reduce((result, elem) => {
if (!result.some((e) => e.clientName === elem.clientName)) {
result.push(elem);
}
return result;
} , []);
}
componentWillMount() {
fetch("https://api.myjson.com/bins/b1i6q", {
method: "GET",
headers: {
Accept: "application/json",
"Content-type": "application/json"
}
/*body: JSON.stringify({
username: '{userName}',
password: '{password}'
})*/
}) /*end fetch */
.then(results => results.json())
.then(data => this.setState({ data: data }));
} //end life cycle
render() {
console.log(this.state.data);
return (
<div>
<div className="container">
<div className="astContainer">
<form>
<div>
<h2>Memeber Selection:</h2>
{["clientName", "siteName", "segmentName"].map(key => (
<div className="dropdown-padding">
<select key={key} className="custom-select">
{this.state.data.map(({ [key]: value }) => (
<option key={value}>{value}</option>
))}
</select>
</div>
))}
</div>
<div className="txt_cfm">
<label for="example-text-input">Modify CFM Rate Factor:</label>
<input
class="form-control"
type="textbox"
id="cfmRateFactor"
name="cfmRateFactor"
value={this.state.cfmRateFactor}
onChange={e => this.change(e)}
/>
</div>
<div>
<div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
export default Ast;
Could I please get some help with this? I'm still very new to using React JS.
You could use Map, it's a data structure for keeping key-value pairs. It will give you best performance for large data.
removeDuplicates(arr) {
const map = new Map();
arr.forEach(v => map.set(v.abc_buildingid, v)) // having `abc_buildingid` is always unique
return [...map.values()];
}
// this hook is better to start fetching data than componentWillMount
componentDidMount() {
fetch("https://api.myjson.com/bins/b1i6q", {
method: "GET",
headers: {
Accept: "application/json",
"Content-type": "application/json"
}
})
.then(results => results.json())
.then(data => this.setState({ data: this.removeDuplicates(data) })); // use the defined method
} //end life cycle
filter won't solve your problem. But reduce will.
You could have the following :
function removeDups(array) {
return array.reduce((result, elem) => {
if (!result.some((e) => e.abc_buildingid === element.abc_buildingid)) {
result.push(elem);
}
return result;
} , []);
}
This one is going to be a long one :)
So here is the idea, I wanna use same html page for two controllers , problem is , that page in insert state wont load , because of ng-repeat="employee in employee" because its non existent in insert controller.
What my repeater does it just fills textboxes , it doesnt repeat anything , its just a single form and it fills information of that one single employee , am i doing this wrong ?
employeeUpdate works like a charm , problem is in employeeInsert , is there a posibility that it can fill textboxes without ng-repeat part , because it does not work without it , but it does fill comboBox/select options without it.
.state('employeeUpdate', {
url: '/employeeUpdate?employeeCode=:param1',
templateUrl: 'pages/employeeUpdate.html',
controller: 'employeeUpdateCtrl',
resolve: {
employeeGatherAll: ['$http', function ($http) {
return $http.jsonp("webserviceSite&procedureName=wsEmployeeGatherAll 'param','param'&callback=JSON_CALLBACK")
.success(function (response) {
return (response)
}).error(function (response) {
console.log("failed");
});
}],
employeeSelectByCode: ['$http','$location', function ($http, $location) {
var employeeCode = $location.search().employeeCode
return $http.jsonp("webServiceSite&procedureName=wsEmployeeSelectByCode 'paramet','parame','" + employeeCode + "'&callback=JSON_CALLBACK")
.success(function (response) {
return (response)
}).error(function (response) {
console.log("failed");
});
}]
}
})
.state('employeeInsert', {
url: '/employeeInsert',
templateUrl: 'pages/employeeUpdate.html',
controller: 'employeeInsertCtrl',
resolve: {
employeeGatherAll: ['$http', function ($http) {
return $http.jsonp("webServiceSiteUrl&procedureName=wsEmployeeGatherAll 'parametar','parametar'&callback=JSON_CALLBACK")
.success(function (response) {
return (response)
}).error(function (response) {
console.log("failed");
});
}],
}
})
So i have selectView as well , where i list all employees, and on click i go to employeeUpdate where i send code trough url as well , my html employeeUpdate page looks something like this :
<div ng-repeat="employee in employee">
<div class="col-md-4">
<label>Employee code</label>
<input type="text" class="form-control" id="txtEmployeeCode" ng-model='employee.employeeCode' />
</div>
<div class="col-md-4">
<label>Status</label>
<select id="Select3" class="form-control" ng-model="employee.statusCode" ng-options="item.code as item.name for item in employeeGather.status">
<option value="">Select status</option>
</select>
</div>
</div>
And these are the controllers
angular
.module('app')
.controller('employeeUpdateCtrl', ['$scope', 'employeeGatherAll', 'employeeSelectByCode', function ($scope, employeeGatherAll, employeeSelectByCode) {
$scope.employee = employeeSelectByCode.data.employee;
$scope.employeeGather = employeeGatherAll.data
}])
.controller('employeeInsertCtrl', ['$scope', 'employeeGatherAll', function ($scope, employeeGatherAll) {
$scope.employeeGather = employeeGatherAll.data
}])
employee.SelectByCode.data.employee[0] was the soulution , without ng-repeat