What resolve is doing in this situation? - javascript

New to ember, I am having trouble making sense of this code:
On the front-end, is a simple form, that is used to submit user text input as feedback
<Form #onSubmit={{perform this.submitFeedback}}>
<TextField
#multiline={{3}}
#placeholder="Additional comments"
#autoFocus={{not #shouldRenderOptions}}
#value={{this.feedbackText}}
#disabled={{this.submitFeedback.isRunning}}
#onChange={{action (mut this.feedbackText)}}
/>
<ButtonGroup>
<Button
#text="Send feedback"
#loading={{this.submitFeedback.isRunning}}
#onClick={{perform this.submitFeedback}}
/>
<Button
#text="Cancel"
#plain={{true}}
#onClick={{action #onCancel}}
/>
</ButtonGroup>
</Form>
Backing it up, on the .js Component I have:
export default class FeedbackFormComponent extends Component {
/**
* Callback when the feedback form is submitted
* Provides `feedbackText` and `wasContentUseful`
* as arguments.
*
* #type {Function}
* #public
*/
onSubmitFeedback = resolve;
#dropTask
submitFeedback = function* submitFeedback() {
let { feedbackText, wasContentUseful, onSubmitFeedback } = this;
yield onSubmitFeedback(wasContentUseful, feedbackText);
};
}
How can I track, what this submission is actually doing? What is resolve doing in a situation like this? onSubmitFeedback = resolve;

Looks like that is referencing a function that acts like Promise.resolve, according to the documentation.
The referenced function has this signature, where it also takes in 2 arguments like onSubmitFeedback does:
resolve (value, label)

Related

Can you use functions from an imported JavaScript library such as Change Case directly in a Vue component's template?

I understand how to import and use Change Case within the <script></script> element of a Vue component, which is just the standard Javascript import covered in the Change Case Github page. However, I would like to use the Change Case functions directly in the template if possible.
Currently, it is my understanding that for dynamic content in the template, in this case generated by v-for running through an array, I must render the return value of a intermediary method from the component's methods section which applies the Change Case function. A method is required for each case type (e.g. camelCase, snakeCase, etc.) I want to render, in this instance one (capitalCase). For example:
// ...
<div
v-for="location in locations"
:key="location.name"
>
<input
type="checkbox"
:id="`select-${location.name}`"
:value="capitalCaseLocationName(location.name)"
v-model="locationsInput"
/>
<label :for="`select-${location.name}`">
{{ capitalCaseLocationName(location.name) }}
</label>
</div>
// ...
methods: {
capitalCaseLocationName(name) {
return capitalCase(name)
}
},
// ...
It would be preferable to somehow import Change Case into the template logic so I could write it like this (no intermediary methods needed):
// ...
<div
v-for="location in locations"
:key="location.name"
>
<input
type="checkbox"
:id="`select-${location.name}`"
:value="capitalCase(location.name)"
v-model="locationsInput"
/>
<label :for="`select-${location.name}`">
{{ capitalCase(location.name) }}
</label>
</div>
// ...
Any chance of that being possible?
As long as you register the imported function as a method you should be able to use it directly in the template.
According to the code, you use Options API, so something like this should do the trick:
import {capitalCase} from "change-case";
...
methods: {
capitalCase,
myOtherMethod () => {...}
}
...
And in the <template>:
<input
type="checkbox"
:id="`select-${location.name}`"
:value="capitalCase(location.name)"
v-model="locationsInput"
/>
The functions need to be defined and passed to the template, that is why even console.log won't work from a template.
You already have an answer with an example, but here's another thing you could do that might make things easier.
You can create a helper like this:
template-helpers.js
export function capitalCase(str) {
return str.split(" ").map(wrd => wrd[0].toUpperCase() + wrd.slice(1)).join(" ")
}
export default {
capitalCase
}
this would make it so that you could use it in a composition/setup like this
import templateHelpers from "../utils/template-helpers.js";
setup(){
return{
...templateHelpers
}
}
in an options API component you could just include it like this
import templateHelpers from "../utils/template-helpers.js";
// ...
methods: {
...templateHelpers,
// other methods
}
// ...
Example
by exporting functions in export default you can destructure them by using methods: { ...templateHelpers
the downside is that it would all the methods every time, but it would make for a more convenient solution. Alternatively, you can pick and chose, since the functions are also exported
import {capitalCase} from "../utils/template-helpers.js";
// ...
methods: {
capitalCase,
// other methods
}
// ...
Vue does have a way to add global definitions, but it's discouraged. This would be done by assigning it to config.globalProperties
https://vuejs.org/api/application.html#app-config-globalproperties
app.config.globalProperties.capitalCase = (str) => {
return str.split(" ").map(wrd => wrd[0].toUpperCase() + wrd.slice(1)).join(" ")

Saving Values to Backend from TextBoxes using React Flux Pattern

I have several text boxes and a save button
Each text box value is loaded using the following approach
{
this.getElement('test3lowerrangethreshold', 'iaSampling.iaGlobalConfiguration.test3lowerrangethreshold',
enums.IASamplingGlobalParameters.ModerationTest3LowerThreshold)
}
private getElement(elementid: string, label: string, globalparameter: enums.IASamplingGlobalParameters): JSX.Element {
let globalParameterElement =
<div className='row setting-field-row' id={elementid}><
span className='label'>{localeHelper.translate(label)}</span>
<div className="input-wrapper small">
<input className='input-field' placeholder='text' value={this.globalparameterhelper.getDataCellContent(globalparameter, this.state.globalParameterData)} />
</div>
</div>;
return globalParameterElement;
}
Helper Class
class IAGlobalParametesrHelper {
public getDataCellContent = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>) => {
return configdata?.find(x => x.key === globalparameter)?.value;
}
}
This works fine. Now the user is allowed to update these text values.And on click of save the changes should be reflected by calling a web api .
I have added an onlick event like this
<a href='#' className='button primary default-size' onClick={this.saveGlobalParameterData}>Save</a>
Now inorder to save the data i need a way to identify the text element which has changed.For that i have added an update method within the Helper class
public updateCellValue = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>,updatedvalue:string) => {
let itemIndex = configdata.findIndex(x => x.key === globalparameter);
configdata[itemIndex] = updatedvalue;
return configdata;
}
and return the updated configdata ,and i plan to call this method in the onchange event of every text box like this
<input className='input-field' placeholder='text' onchange={this.setState({ globalParameterData: this.globalparameterhelper.updateCellValue(globalparameter, this.state.globalParameterData, (document.getElementById(elementid) as HTMLInputElement).value})}
But this does not seem like a correct approach as there are number of syntactical errors. I initially got the data using an actioncreator like this.Please advice.
samplingModerationActionCreator.getGlobalParameters();
samplingModerationStore.instance.addListener(samplingModerationStore.SamplingModerationStore
.IA_GLOBAL_PARAMETER_DATA_GET_EVENT,
this.getGlobalParameterData);
}

Declaring function inside class component vs inside functional component

I am playing with function syntax inside and outside class components. Can anyone explain to me why the print function works when written like this
const UploadButton = (props)=> {
const fileName = 'myfile';
props.getFileName(fileName)
function print(){console.log('onClick worked')}
return(
<div>
<input onClick= {print()} type="file" id = {fileName}/>
</div>
)
}
but when i write it like i would when declaring it inside a class component:
print(){console.log('onClick worked')}
i get this error
Line 10: Parsing error: Unexpected token, expected ";"
8 | props.getFileName(fileName)
9 |
> 10 | print(){console.log('onClick worked')}
| ^
This behavior is not tied with React but fundamentally is a method vs. function thing in JavaScript.
When you declare functions with some context it becomes a method. So, In a class setup, the functions are actually methods.
In Javascript, it is possible to declare a function within another function, that is why this works
const UploadButton = (props)=> {
const fileName = 'myfile';
props.getFileName(fileName)
function print(){console.log('onClick worked')}
return(
<div>
<input onClick= {print()} type="file" id = {fileName}/>
</div>
)
}
But when you don't specify the function keyword and the declaration is not inside of class it throws error.
print(){console.log('onClick worked')}
Parsing error: Unexpected token, expected ";"
If you rather used an arrow function here print=()=>{console.log('onClick worked')}, it would work because its a function expression and is treated as a normal variable declaration scoped to the enclosing function.
print(){console.log('onClick worked')}
I think when you write this in a functional component the compiler does not know that you are trying to define a function and it is rather trying to execute the print function, hence it is expecting a ';'
However, In class based components when you define a function using the above syntax, when the class is converted to a function, the print method will be added to its prototype.
One issue that you're having with your functional component is that you're calling the print function, then passing whatever it returns, which is undefined in this case, to the onClick handler of your input element.
Your JSX for the input element should look like this:
const UploadButton = (props)=> {
// ...
return (
<div>
<input onClick={print} type="file" id={fileName}/>
</div>
)
}
When dealing with class components, however, your UploadButton component, should look like the following:
class UploadButton extends React.Component {
print() {
console.log('onClick worked')
}
render() {
// ...
this.props.getFileName(fileName)
return (
<div>
<input onClick={this.print} type="file" id = {fileName}/>
</div>
)
}
}
Also, you probably shouldn't be using an input element as your UploadButton. Just use a button element instead, something like the following example:
<form>
<div>
<label for="file">Choose file to upload</label>
<input type="file" id={fileName} />
</div>
<div>
<!--Should be something along the lines of `this.handleSubmit`
rather than `this.print`, but you get the idea-->
<button onClick={this.print}>Submit</button>
</div>
</form>

React components as instances like in OO programming

I created React component using React.creatClass ()
module.exports = React.createClass({ // input-field-units.jsx is the file name
displayName: 'input-field-units',
render: function () {
return (
<div >
<form className="form-inline" role="form">
<div className="implement-width-select">
<input id={inputid} type="number" className="form-control" onChange={this.onChangeTest}></input>
<div className="form-group">
<select id="implement-width-unit" className="form-control" defaultValue="m" onChange={this.onChangeTest} >
<option value="m" >m</option>
<option value="mm">mm</option>
<option value="ft">ft</option>
</select>
</div>
</div>
</form>
</div>
);
},
componentWillMount: function(){
inputid = this.props.inputid;
console.log("component: " + inputid);
},
onChangeTest: function(){
$(document).ready(function () {
var _unit = document.getElementById("implement-width-unit").value;
var _widthValue = document.getElementById(inputid).value;
//processing of code here..
});
I intend to call this component like objects in C# where values of properties are not shared if this is called several times. here inputid is set from this.props.inputid in componentWillMount()
Im using this component on several places in my application (distributed code is in a single file). In my .jsx file I am doing this
var InputFieldUnitsComponent = require('../Components/input-field-units.jsx');
var ImplementWidthID = "Implement-Width-ID", againWidthID = "again-width-id";
module.exports = React.createClass({
displayName: 'PathPlannerSidebarHeader',
render: function () {
return (
<div>
<h2 className="sidebar-header-subtitle">Implement Width</h2>
<InputFieldUnitsComponent
inputid= {ImplementWidthID} // 1st call
/>
<h2 className="sidebar-header-subtitle">again Width</h2>
<InputFieldUnitsComponent
inputid= {againWidthID}
/>
</div>
);
//....
})
so that everytime I have a new this.props.inputid to set id of
but the problem is this.props.inputid maintains same value change and hold the last value. eg in this case inputid will have "again-width-id" even when I want to use for 1st time I called the component.
In short I like OO behavior where the properties of objects are not shared with each other.
Please ask if this doesn't make sense I will explain
You essentially made inputid a global variable by not declaring it with var (or const or let).
You could say this.inputid in componentDidMount, but that doesn't make a lot of sense: why have the same value as both this.inputid and this.props.inputid
It's simpler to just use this.props.inputid consistently. If you want to simplify render(), define it as a local variable in there.
I suggest to install eslint and enable it in your editor to find this kind of errors.
You also need to update the function onChangeTest. It's not correct to try something like:
onChangeTest: function() {
$(document).ready(function () {
var _widthValue = document.getElementById(this.inputid).value;
});
}
onChangeTest is a method of your react class, but the anonymous function that you're passing to ready() isn't, and it can't refer to your react component via this... unless you bind it!
onChangeTest: function() {
$(document).ready(function () {
var _widthValue = document.getElementById(this.inputid).value;
}.bind(this));
}
or with the ES6 syntax:
onChangeTest: function() {
$(document).ready(() => {
var _widthValue = document.getElementById(this.inputid).value;
});
}
Obligatory reading: How does the "this" keyword work?

Using serverside HTML-templates with ReactJS

I'm struggling with Reactjs and component rendering.
Basically I've regular html-templates at the server and I'm trying to use them as a JSX-components with the React. Otherwise it works just fine, but I'm not able to fire the events for example: this.handleSubmit.
How to render the loaded template as a React-element?
//Template /index.html
<form onSubmit={this.handleSubmit}>
<input type="text">
<input type="submit"
</form>
//Template loader
var App = React.createClass({
componentDidMount: function() {
this.updateContent();
},
updateContent: function(){
/**
* Loads the template from the server and sets
* a new state
*/
var url = this.props.source.slice(1);
$.get(url, function(result) {
var html = result;
if (this.isMounted()) {
this.setState({
content: html
});
}
}.bind(this));
},
handleSubmit: function(){
console.log('Submit fired');
}
render: function() {
var converter = new HTMLtoJSX({createClass: false});
var jsx = '/** #jsx React.DOM */ ' + converter.convert(this.state.content);
return (
<div>
{JSXTransformer.exec(jsx)}
</div>
);
});
React.render(
<App source="#/index.html" />,
mountPoint
);
JSX isn't templates for a markup language, it's a syntax extension to the JavaScript programming language. The distinction is important here.
You need to convert JSX to JS (usually done when building your project). If we modify your code to be valid JSX it looks like this:
<form onSubmit={this.handleSubmit}>
<input type="text" />
<input type="submit" />
</form>
And when run through the jsx tools the output is the following JavaScript expression.
React.createElement("form", {onSubmit: this.handleSubmit},
React.createElement("input", {type: "text"}),
React.createElement("input", {type: "submit"})
)
You need to execute this code in render, with the correct this context. You could do this by wrapping the above in a function before serving it to the client:
function renderThingy(){
React.createElement("form", {onSubmit: this.handleSubmit},
React.createElement("input", {type: "text"}),
React.createElement("input", {type: "submit"})
)
}
And calling that in render:
render: function() {
return (
<div>
{renderThingy.call(this)}
</div>
);
}
This is of course confusing, and it's not apparent if handleSubmit is used by anything. Then of course, there's the issue of loading code asynchronously... I'd rather not delve into that here.
This also severely limits what you can do in your 'template', and various other problems will pop up.
tl;dr don't do this
If you want to use JSX on the server: cool, you just need a JS runtime, and a component. React.renderToString or React.renderToStaticMarkup will take care of actually giving you valid html.
The template should be precompiled using React.renderToString(), then the html returned from the function has all the extra DOM attributes such as data-react-id needed to make a reconciliation with the client.
This is because the onSubmit={this.handleSubmit} in your template doesn't have the react data associated, react doesnt care/know about it.
React can render clean html too without the bloat using React.renderToStaticMarkup() function;
Take a look here http://facebook.github.io/react/docs/top-level-api.html#react.rendertostring

Categories