I am trying to add React to an existing Rails 5.1 application, but I'm getting this error: Uncaught ReferenceError: exports is not defined.
I'm using webpacker. This is the contents of my application.js file:
//= require react
//= require react_ujs
//= require components
In my components directory, I have the file register.jsx:
class Register extends React.Component {
render(){
return(
<div>
<h1>Register a Group</h1>
</div>
)
}
}
export default Register
This file processes to this, as viewed in Chrome developer tools:
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
// import React from 'react';
var Register = (function (_React$Component) {
_inherits(Register, _React$Component);
function Register() {
_classCallCheck(this, Register);
_get(Object.getPrototypeOf(Register.prototype), "constructor", this).apply(this, arguments);
}
_createClass(Register, [{
key: "render",
value: function render() {
return React.createElement(
"div",
null,
React.createElement(
"h1",
null,
"Register a Group"
)
);
}
}]);
return Register;
})(React.Component);
exports["default"] = Register;
module.exports = exports["default"];
The uncaught reference is being thrown at the very first line.
Any ideas are greatly appreciated!
React should be loaded from your application pack in app/javascripts/packs/application.js, not from app/assets/javascripts/application.js, as the default JavaScript compressor that Sprockets uses doesn't support ES6.
Your React components should be referenced from app/javascripts/components as well.
Also make sure you're importing React correctly in your component files:
import React from 'react-dom'
export default class Register extends React.Component {
render() {
return (
<div>
<h1>Register a Group</h1>
</div>
)
}
}
Related
I need to set the property to DataSet during onInit, to change the visiblity of some controls in my View. I could solve this problem with setting the visibility dynamically in controller. But I want to use the expression binding and the visible property in the View to set visibilites.
I'm getting an error in the function OnStartSetVisibilites. self.getView().getBindingContext() returns UNDEFINED. Without the sPath, I can't use setProperty. And without setProperty, my View-Controls don't know the visible-value.
How to fix this?
View:
<uxap:ObjectPageSubSection visible="{= ${Responsible} === '1'}" id="leader">
</uxap:ObjectPageSubSection>
OnInit in View-Controller:
onInit: function () {
var startupParameters = this.getOwnerComponent().getComponentData().startupParameters;
var sWorkitem = startupParameters.TASK[0];
this.setModel(this.getOwnerComponent().getModel());
this.getModel().metadataLoaded().then(function () {
var sObjectPath = this.getModel().createKey("DataSet", {
Workitem: sWorkitem
});
this.getView().bindElement({
path: "/" + sObjectPath
});
}.bind(this));
var self = this;
var model = this.getOwnerComponent().getModel();
this.getModel().read("/CharSet", {
success: function (response) {
$.sap.Chars = response.results;
self.onStartSetVisibilities(model, self);
}
});
// self.getView().attachAfterRendering(function () {
// self.onStartSetVisibilities(model, self);
// });
}
OnStartSetVisibilities:
onStartSetVisibilities: function (model, self) {
var char = model.getProperty(ā€˛GeneralData/Char");
if (char !== "" || char !== null) {
model.setProperty(self.getView().getBindingContext().sPath + "/Responsible",
this.getResponsibleForChar(char));
}
}
I put together some code which might solve your issue (it's untested so it may contain syntax errors!).
I introduced the concept of Promises which simplifies the asynchronous behavior of JS. I also replaced some of the inner functions with Arrow functions so you don't have to deal with that or self. Arrow functions basically use the this of the scope they are defined within.
Your app should now have a proper flow.
First you bind the view.
After the view is bound you read the CharSet.
After the data is read you set the visibility stuff
onInit: function () {
const startupParameters = this.getOwnerComponent().getComponentData().startupParameters;
const sWorkitem = startupParameters.TASK[0];
this._bindView(sWorkitem)
.then(() => this._readCharSet())
.then(() => this._setVisibilities())
},
_bindView: function (sWorkitem) {
return new Promise((resolve) => {
const oModel = this.getOwnerComponent().getModel();
oModel.metadataLoaded().then(() => {
const sPath = "/" + oModel.createKey("DataSet", {
Workitem: sWorkitem
});
this.getView().bindElement({
path: sPath,
events: {
change: resolve,
dataReceived: resolve
}
});
});
});
},
_readCharSet: function () {
return new Promise((resolve) => {
const oModel = this.getOwnerComponent().getModel();
oModel.read("/CharSet", {
success: resolve
});
});
},
_setVisibilities: function () {
const oModel = this.getOwnerComponent().getModel();
const sChar = oModel.getProperty("GeneralData/Char");
if (sChar) {
// ...
}
}
I am rendering extension on the Work item page using
<WebpageControlOptions AllowScript="true" ReloadOnParamChange="true">
<Link UrlRoot="http://.../extension/Validate-extension/1.0.69/assetbyname/workItemNotifications.html"/>
</WebpageControlOptions>
Following is the html/js code:
var workItemID = 0;
VSS.init({
explicitNotifyLoaded: true,
usePlatformScripts: true
});
VSS.ready(function () {
var currentContext = VSS.getWebContext();
VSS.register(VSS.getContribution().id, function (context) {
return {
// event handlers, called when the active work item is loaded/unloaded/modified/saved
onFieldChanged: function (args) {
if (!changedFields[args.id]) {
changedFields[args.id] = [];
changedFieldCount[args.id] = 0;
}
$.each(args.changedFields, function (key, value) {
if (!changedFields[args.id][key]) {
changedFields[args.id][key] = value;
changedFieldCount[args.id]++;
}
});
},
onLoaded: function (args) {
console.log("OnloadNotification");
VSS.require(["TFS/WorkItemTracking/Services"], function (workItemServices) {
workItemServices.WorkItemFormService.getService().then(function (workItemFormSvc) {
if (workItemFormSvc.hasActiveWorkItem()) {
console.log("Active work item is available.");
workItemFormSvc.getFieldValues(["System.Id"]).then(
function (value) {
var val = JSON.stringify(value);
$.each(value, function (key, values) {
if(key == "System.Id"){
workItemID = values;
}
});
});
}
else {
console.log("Active work item is NOT available.");
}
});
});
},
onUnloaded: function (args) {
},
onSaved: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onReset: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onRefreshed: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
}
};
});
VSS.notifyLoadSucceeded();
});
$(document).ready(function () {
$("#btnValidate").click(function () {
var getResponse = ValidateUser();
VSS.require(["TFS/WorkItemTracking/Services"], function (_WorkItemServices) {
var wiServiceNew = _WorkItemServices.WorkItemFormService.getService();
wiServiceNew.setFieldValue("System.Title", "Title set from your group extension!");
});
});
});
2 things which I am trying to achieve
After button click event to validate user, I have to access the Work Item fields after successful validation. Unable to access _WorkItemServices.
Not able to to get the Work Item fields.
When I set workItemID variable OnLoad event, it resets to 0 when a tab is clicked, value is not getting retained which is set OnLoad.
You may try to interact with the IWorkItemFormService service. For example:
import {
IWorkItemChangedArgs,
IWorkItemFieldChangedArgs,
IWorkItemFormService,
IWorkItemLoadedArgs,
WorkItemTrackingServiceIds
} from "azure-devops-extension-api/WorkItemTracking";
Check the sample here:
https://github.com/microsoft/azure-devops-extension-sample/blob/master/src/Samples/WorkItemFormGroup/WorkItemFormGroup.tsx
I am using chartjs (with the dart interface https://pub.dartlang.org/packages/chartjs) and trying to make it deferred by injecting a <script src="chartjs.js"></script> into the head section and awaiting it's load event to then use the lib.
I am getting this exception: Cannot read property 'Chart' of undefined.
It does not happen when the script is within the head of the html before dart.
So, is it possible to load a JS lib after Dart loaded?
this is a problem in DDC.
It addeds require.js to the HTML and conflicts with other libs.
https://github.com/dart-lang/sdk/issues/33979
The solution I've found is to manually remove the header section that uses requirejs from the third-party lib you want to use.
For example, take chartjs: https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.js
You remove this two lines:
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(function() { try { return require('moment'); } catch(e) { } }()) :
typeof define === 'function' && define.amd ? define(['require'], function(require) { return factory(function() { try { return require('moment'); } catch(e) { } }()); }) :
Then the file can be lazily added to the DOM without conflicts.
This is my code to lazily fetch scripts:
class ClientUtils {
static final _scriptFetched = <String, Future<bool>>{};
static ScriptElement _scr(String url) => new ScriptElement()
..async = true
..type = 'text/javascript'
..src = url;
static Future<bool> fetchScript(String url,
{String contextCheck}) async {
bool shouldCheck = contextCheck?.isNotEmpty == true;
hasContext() => js.context.hasProperty(contextCheck) &&
js.context[contextCheck] != null;
if (shouldCheck && hasContext())
return true;
if (!_scriptFetched.containsKey(url)) {
Completer<bool> c = new Completer<bool>();
if (!shouldCheck) {
ScriptElement s = _scr(url)
..onLoad.forEach((Event e) {
c.complete(true);
});
document.body.children.add(s);
} else {
Timer.periodic(Duration(milliseconds: 300), (t) {
if (hasContext()) {
t.cancel();
}
c.complete(true);
});
document.body.children.add(_scr(url));
}
_scriptFetched[url] = c.future;
}
return _scriptFetched[url];
}
}
found a better way!
lets remove the define variable after dart loads, then any third-party lib works when added async :D
add this to your main():
import 'dart:js';
void main() {
context.callMethod('fixRequireJs');
}
and in your index.html:
<script type="text/javascript">
window.fixRequireJs = function()
{
console.log('define is ', typeof define);
if (typeof define == 'function') {
console.log('removing define...');
delete define;
window.define = null;
}
}
</script>
You can try the deferred as syntax:
import 'package:chartjs/chartjs.dart' deferred as chartjs;
void main() {
chartjs.loadLibrary().then(() { ... });
}
I have weird issue when trying to create a custom autocomplete editor.
Basicly what I've done is I've pulled the built-in AutocompleteEditor class and refactored it to plain ES6, and renamed the class to ProductSelectEditor. No modifications to the code logic.
When I try to use it, I'm getting error "Cannot read property 'onCommit' of undefined" when handleChange() is called:
handleChange() {
this.props.onCommit(); // props undefined
}
Now if i replace the editor with the real built-in AutocompleteEditor, it works just fine. I can't see any straight reason, why my custom version does not work, when only alterations I'm doing are refactoring the code away from TypeScript, renaming the class, and eventually exporting the class out as default?
Any clues on what I'm not understanding here?
Below is the whole refactored code
import React from 'react'
import ReactDOM from 'react-dom'
import ReactAutocomplete from 'ron-react-autocomplete';
import PropTypes from 'prop-types';
import '../css/ron-react-autocomplete.css'
const { shapes: { ExcelColumn } } = require('react-data-grid')
let optionPropType = PropTypes.shape({
id: PropTypes.required,
title: PropTypes.string
});
export default class ProductSelectEditor extends React.Component {
static propTypes = {
onCommit: PropTypes.func,
options: PropTypes.arrayOf(optionPropType),
label: PropTypes.any,
value: PropTypes.any,
height: PropTypes.number,
valueParams: PropTypes.arrayOf(PropTypes.string),
column: PropTypes.shape(ExcelColumn),
resultIdentifier: PropTypes.string,
search: PropTypes.string,
onKeyDown: PropTypes.func,
onFocus: PropTypes.func,
editorDisplayValue: PropTypes.func
};
static defaultProps = {
resultIdentifier: 'id'
};
handleChange() {
this.props.onCommit();
}
getValue() {
let value;
let updated = {};
if (this.hasResults() && this.isFocusedOnSuggestion()) {
value = this.getLabel(this.autoComplete.state.focusedValue);
if (this.props.valueParams) {
value = this.constuctValueFromParams(this.autoComplete.state.focusedValue, this.props.valueParams);
}
} else {
value = this.autoComplete.state.searchTerm;
}
updated[this.props.column.key] = value;
return updated;
}
getEditorDisplayValue() {
let displayValue = {title: ''};
let { column, value, editorDisplayValue } = this.props;
if (editorDisplayValue && typeof editorDisplayValue === 'function') {
displayValue.title = editorDisplayValue(column, value);
} else {
displayValue.title = value;
}
return displayValue;
}
getInputNode() {
return ReactDOM.findDOMNode(this).getElementsByTagName('input')[0];
}
getLabel(item) {
let label = this.props.label != null ? this.props.label : 'title';
if (typeof label === 'function') {
return label(item);
} else if (typeof label === 'string') {
return item[label];
}
}
hasResults() {
return this.autoComplete.state.results.length > 0;
}
isFocusedOnSuggestion() {
let autoComplete = this.autoComplete;
return autoComplete.state.focusedValue != null;
}
constuctValueFromParams(obj, props) {
if (!props) {
return '';
}
let ret = [];
for (let i = 0, ii = props.length; i < ii; i++) {
ret.push(obj[props[i]]);
}
return ret.join('|');
}
render() {
let label = this.props.label != null ? this.props.label : 'title';
return (<div height={this.props.height} onKeyDown={this.props.onKeyDown}>
<ReactAutocomplete search={this.props.search} ref={(node) => this.autoComplete = node} label={label} onChange={this.handleChange} onFocus={this.props.onFocus} resultIdentifier={this.props.resultIdentifier} options={this.props.options} value={this.getEditorDisplayValue()} />
</div>);
}
}
Alright, after few hours of poking and mangling found the reason for the props to be undefined. Apparently after stripping out the Typescripts, I needed to re-bind 'this' in order to get the correct context:
<ReactAutocomplete ... onChange={this.handleChange.bind(this)} ... />
I'm using angularjs to bring some data from server,
it's works perfectly.
Here is the code:
myAppcontroller("AgentCtrl", function ($scope, leadsService) {
$scope.showUsers = false;
$scope.cityName = { 'query': ''};
$scope.findAgent = function() {
leadsService.get("/api/usersapi/agents/" + $scope.cityName.query).then(function(out) {
$scope.agents = out;
$scope.showUsers = true;
$scope.selectedOption = $scope.agents[0];
});
};
$scope.init = function (cityName) {
$scope.cityName.query = cityName;
if ((typeof cityName !== "undefined")) {
$scope.findAgent();
}
};
$scope.$watch('cityName.query', function (newValue, oldValue) {
$scope.cityName.query.watch = newValue;
});
});
Now I have a validation error in Chrome... (I'm using jQuery validation).
Here is the code I'm using to disable this error:
$.validator.addMethod('date', function (value, element, params) {
if (this.optional(element)) {
return true;
}
var isValid = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2} \d{2}:\d{1,2}:\d{1,2}$/.test(value);
alert(isValid);
return isValid;
}, '');
But when I use the jquery code angularjs stops working...
Some one have met this issue??? If so how to solve it?