ReactJs: Passing a prop and using it within a map() - django

I'm trying to take a user inputted code and compare it to code within my database. Right now I can bring the code and display it outside the map function but when I try to add it, it doesn't work. here is my database:
[
{
"dwelling_code": "ABC-XYZ",
"dwelling_name": "Neves Abode",
"has_superAdmin": true,
"room": []
}
This is the parent component:
class Dwel2 extends Component {
state = {
house: [],
selectedMovie: null,
data: "ABC-XYZ"
}
componentDidMount() {
fetch('Removed for question', {
method: 'GET',
headers: {
}
}).then(resp => resp.json())
.then(resp => this.setState({ house: resp }))
.catch(error => console.log(error))
}
houseClicked = h => {
console.log(h)
}
render() {
return <div>
<EnterCode dataFromParent={this.state.data}
house={this.state.house}
houseClicked={this.house} />
</div>
}
}
This is the child component:
function EnterCode(props) {
return (
<div>
<div>
*THIS BIT DISPLAYS THE CODE*{props.dataFromParent}
</div>
{props.house.map(house => {
var test = house.dwelling_name
var code = house.dwelling_code
if (code === {props.dataFromParent}) {
test = "Test"
}
return (
<React.Fragment>
<div>{test}</div>
</React.Fragment>
)
})}
</div>
)
}
I just want to compare the code in the database to the code defined in the parent component. Here is the error that's coming up this is in the child component.
Line 17:31: 'dataFromParent' is not defined no-undef

You made a tiny mistake in the if statement. You put the props.dataFromParent in brackets, which in the context of JSX would be required, but in the context of JS means creating an object, which is clearly wrong.
if (code === props.dataFromParent) {
test = "Test"
}
Hope this helps :)

Related

How to check if conditional rendering is shown after selecting an option from a select list with React Testing Library?

I'm trying to test my component that has the following conditional rendering:
const MyComponent = () => {
const [isVisible, setIsVisible] = (false);
if(selectedOption == 'optionOne')
setIsVisible(true);
else
setIsVisible(false);
return (
<div>
<Select data-testid="select1" selectedOption={selectedOption} />
{isVisible ? <Select data-testid="select2" selectedOption={anotherSelectedOption} /> : null }
</div>
)}
If selectedOption in select1 is 'optionOne', then select2 shows up.
Here is how I am testing it:
describe('Testing', () => {
let container: ElementWrapper<HTMLElement>;
const testState = {
userChoice1: {
selectedOption: ['optionOne'],
},
userChoice2: {
selectedOption: ['test1', 'test2'],
},
} as AppState;
beforeEach(() => {
container = render(<MyComponent/>, testState);
});
it('should show select2 if optionOne is selected', async () => {
const { getByTestId, getAllByTestId } = render(<MyComponent/>);
expect(container.find('span').getElement().textContent).toBe("optionOne"); // this successfully finds select1 with optionOne selected, all good
await screen.findAllByTestId('select2')
expect(screen.getAllByTestId('select2')).toBeInTheDocument();
});
In the testing above, as select1 has optionOne selected, I expect to select2 to show up. However, I am getting an error Unable to find an element by: [data-testid="select2"]. It also returns the whole HTML body, where I see select1 element with optionOne selected, but no select2 at all as it seems to still be hidden.
What am I missing here? How can I unhide select2 within the unit test?

Vue.js, How to get a list of latitude and longitude of a nested json file troughouth a function?

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]
}

Kendo Multi-select in cascading scenario unable to populate initial values

I'm using Telerik for MVC and trying to get the multi-select to populate with the initial values in an Edit scenario.
<script>
function filterProducts() {
return {
manufacturerId: $("#ServiceBulletinItem_ManufacturerId").val()
};
}
function onManufacturerChange(e) {
var v = e.sender.dataItem().Value;
$.post("#Url.Action("GetCascadeProducts", "Components")", { manufacturerId: v }, function (result) {
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.setDataSource(result)
});
}
function InitialPopulate(manId) {
$.post("#Url.Action("GetCascadeProducts", "Components")", { manufacturerId: manId }, function (result) {
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.setDataSource(result)
});
}
$(document).ready(function () {
$('.control-datepicker').Zebra_DatePicker();
var m = $("#ServiceBulletinItem_ManufacturerId").val();
InitialPopulate(m);
});
</script>
<div class="form-group">
#Html.LabelFor(m => m.ManufacturerList, "Manufacturer", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#(Html.Kendo().DropDownListFor(m => m.ServiceBulletinItem.ManufacturerId)
.HtmlAttributes(new { #class = "col-md-6 form-control" })
.Filter("contains")
.DataValueField("Value")
.DataTextField("Text")
.BindTo((IEnumerable<SelectListItem>)Model.ManufacturerSelectList)
.HtmlAttributes(new { style = "width:70%;" }).Events(e =>
{
e.Change("onManufacturerChange");
})
)
</div >
</div >
<div class="form-group">
#Html.LabelFor(m => m.ProductList, "Product", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#(Html.Kendo().MultiSelectFor(m => m.ServiceBulletinItem.ApplicableProducts)
.AutoClose(false)
.DataTextField("ProductName")
.DataValueField("ProductId")
.Placeholder("Select products...")
)
</div>
</div>
I'm trying to populate the manufacturer drop down and the Product multiSelect. The ApplicableProducts item is an IEnumerable representing the ProductId's of all those previously selected and I know that when I select the manufacturer and it calls the GetCascadeProducts controller method it will return back a collection of ProductId and ProductName for all the manufacturers products of which those productId is the ApplicableProducts property should exist.
On document.ready I can call the InitialPopulate method with the manufacturerID which will populate the multiSelect items but can't seem to populate the initial values.
I couldnt get the binding working correctly so ended up using
#(Html.Kendo().MultiSelect()
.Name("ServiceBulletinItem_ApplicableProducts")
.AutoClose(false)
.DataTextField("ProductName")
.DataValueField("ProductId")
.Placeholder("Select products 2...")
.AutoBind(false)
)
and then on the using the following code on document ready to make an ajax call to populate the manufacturer and product controls
function PopulateProductsInitial(manId) {
$.post("#Url.Action("GetCascadeProducts", "Components")", { manufacturerId: manId }, function (result) {
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.setDataSource(result);
var s = $("#ServiceBulletinItem_Id").val();
$.post("#Url.Action("GetSBProducts", "ServiceBulletins")", { Id: s}, function (result) {
var arr = [];
result.forEach(function (element) {
arr.push(element.ProductId);
});
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.value(arr);
});
});
}
}
$(document).ready(function () {
//Populate Initial Values
PopulateProductsInitial($("#ServiceBulletinItem_ManufacturerId").val());
$('#YourButton').click(SendForm);
});
The problem then became sending the selected items back to the controller when the edit was complete which again seemed convoluted because the control was not bound and therefore I had to make an Ajax call to submit the data.
function SendForm() {
var items = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect").value();
//Manipulate into ServiceBulletinViewModel for the save
var data = {
Id: $("#ServiceBulletinItem_Id").val(),
ServiceBulletinItem: {
Id: $("#ServiceBulletinItem_Id").val(),
ManufacturerId: $("#ServiceBulletinItem_ManufacturerId").val(),
IssueDate: $('#ServiceBulletinItem_IssueDate').val(),
Heading: $('#ServiceBulletinItem_Heading').val(),
Details: $('#ServiceBulletinItem_Details').val(),
Url: $('#ServiceBulletinItem_Url').val(),
SelectedProducts: items
}
}
$.ajax({
type: 'POST',
url: '/ServiceBulletins/Edit',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (result) {
//Your success code here..
if (result.redirectUrl != null) {
window.location = result.redirectUrl;
}
},
error: function (jqXHR) {
if (jqXHR.status === 200) {
alert("Value Not found");
}
}
});
}
It all seemed a lot more convoluted than any of the demo's that teleriks and I couldnt find any good examples of binding from remote sources which looked similar.
As the binding is convention based I'm wondering if its possible to simplify the ajax calling for the post functionality with the correct naming of the controls so that I can simply get the selected items on the multiselect control or if the ajax post is the way to go.

How to unit test forms with Sinon and Chai

I am using Chai, Sinon, and Mocha to test.
I am using Redux-Forms, along with ReactJS.
I want to test what happens after I click submit on a Forgot Password page.
Here's my code so far:
react file:
propTypes: {
fields: React.PropTypes.object.isRequired,
message: React.PropTypes.string.isRequired,
handleSubmit: React.PropTypes.func.isRequired,
},
renderForm: function() {
const { fields: {email}, handleSubmit, isFetching } = this.props;
const iconClass = "fa fa-star-o";
return(
<form form="forgotPassword" name="forgotPassword" className="stack-input">
<ReduxFormTextInput
{...email}
floatingLabelText="Email Address" />
<div className="clearfix" />
<div className="form-footer">
<ButtonSpinner spinner={isFetching} onClick={handleSubmit} ripple={true} raised={true} primary={true} >
<i className={iconClass} />Send
</ButtonSpinner>
</div>
</form>
);
},
renderMessage: function() {
return(
<div>
<i className="fa fa-exclamation-circle" style={{marginRight: '4px'}}/>
If your email is in the system, then it will be sent.
</div>
);
},
//Checks if user has submitted email.
emailSubmit: function(){
var locus = this, props = locus.props;
if(props.message === ''){
return null;
}
else if(props.message === 'SENT'){
return true;
}
return null;
},
render(){
var locus = this, props= locus.props;
return(
<div className="page-wrap">
<div className="page-column">
<h2>Forgot Your Password</h2>
{this.emailSubmit() ? this.renderMessage(): this.renderForm()}
</div>
</div>
);
}
unittest file:
describe('ForgotPasswordForm', () => {
const component = setup({
fields: {
email: {
onChange: spy(),
onBlur: spy(),
onFocus: spy()
}
}, // React.PropTypes.object.isRequired,
message: '', // React.PropTypes.string.isRequired,
handleSubmit: spy() // React.PropTypes.func.isRequired,
//onClearMessage:spy() //, React.PropTypes.func.isRequired
}),
domRoot = TestUtils.findRenderedDOMComponentWithClass(component, 'page-wrap'),
title = TestUtils.findRenderedDOMComponentWithTag(component, 'h2'),
submitButton = TestUtils.findRenderedDOMComponentWithClass(component, 'material-D-button'),
form = TestUtils.findRenderedDOMComponentWithTag(component, 'form'),
inputs = TestUtils.scryRenderedDOMComponentsWithTag(component, 'input'),
emailInput = inputs[0];
This test keeps failing, despite multiple attempts. I am not experienced with Spy(), so I'm not sure if I am suppose to be using calledWith.
it ('should display "If your email is in the system, then it will be sent." on submit', () => {
TestUtils.Simulate.change(emailInput, {target: {value: 'test#email.com'}});
TestUtils.Simulate.click(submitButton);
expect(domColumn.text).to.equal("Forgot Your Password");
});
This is the response I get.
+"If your email is in the system, then it will be sent."
- -"Forgot Your PasswordSend"
I used innerHTML to get a sense of what's being populated after the click, and I don't think the click is even registering.
When I try to do TestUtils.Simulate.change(emailInput, {target: {value: 'test#email.com'}});, it doesn't work. I have to populate the value of the email in the component.
You should be assigning your handleSubmit spy to a constant so you can at least be able to check whether it's getting called. (Probably the same for the other spies).
const handleSubmitSpy = spy()
const component = setup({
...
handleSubmit: handleSubmitSpy
Now you can check expect(handleSubmitSpy).toHaveBeenCalled().

ReactJS modify parent state from child component

I'm trying to remove an item from my state array when clicked. At the moment I have an onclick listener which calls a function passed into the props. However I get a warning: bind(): React component methods may only be bound to the component instance. See App... and it does not remove the item.
Thanks for any help regarding this issue! It has pretty much ground my progress to a halt.
(function (React) {
var data = [
'Go to work',
'Play Albion Online',
'Keep learning React'
]
var App = React.createClass({
getInitialState: function () {
return {data: []}
},
componentWillMount: function () {
this.state.data = data;
},
removeItem: function (i) {
console.log(i);
},
render: function () {
return (
<ToDoList onRemoveItem={this.removeItem} tasks={this.state.data} />
)
}
});
var ToDoList = React.createClass({
render: function () {
var scope = this;
var tasks = this.props.tasks.map(function (task, i) {
return <ToDo onClick={scope.props.onRemoveItem.bind(this, i)} key={task} task={task} />
});
return (
<ul>
{tasks}
</ul>
)
}
});
var ToDo = React.createClass({
render: function () {
return (
<li>{this.props.task}</li>
)
}
});
React.render(<App />, document.getElementById('example'));
})(React);
React actually auto-binds methods to the current component:
http://facebook.github.io/react/blog/2013/07/02/react-v0-4-autobind-by-default.html
In the TodoList component, rather than:
scope.props.onRemoveItem.bind(this, i)
Try:
scope.props.onRemoveItem.bind(null, i)
By providing null instead of this you'll allow React to do its own thing. Also you need to actually use the onClick handler:
<li onClick={this.props.onClick}>{this.props.task}</li>