transition from ember service in Ember.js - javascript

generateDeviceCode(response) {
let {
encryptedactivationmessage,
macvalueactivationmessage,
encryptioncounter
} = response.registerDetails;
let softtoken = this.get('softtoken');
softtoken.callSoftTokenService(
'generateDeviceCode',
macvalueactivationmessage,
encryptedactivationmessage,
encryptioncounter
)
.then(response => {
let {
deviceCode
} = response;
let userId = this.get('userId') || this.get('userPreference.userId');
let groupId = this.get('groupId') || this.get('userPreference.groupId');
let payload = {
deviceCode,
authorizationCode: this.get('memoizedFields.authorizationCode'),
tokenSerialNumber: this.get('memoizedFields.tokenSerialNumber'),
userId,
groupId,
notificationId: 'NA'
};
this.navigation.toRoute('digital.pinRegistrationFlow', {
queryParams: {
initialState: 'setPin',
data: payload
}
});
})
.catch(err => {
Logger.error(err);
});
},
When I try to go to ember route from ember service. I get the following error Cannot read property toRoute of undefined. But when I try the same code in the controller it works fine. Can anyone help me here please ?

If you are on a current-ish version of Ember you can inject the router as a service and use it to transition.
export default Ember.Service.extend({
router: Ember.inject.service(),
actions: {
doIt() {
this.get('router').transitionTo('somewhere');
}
}
});

Related

How to access data in mounted() with nuxt.js

I tried to do a for loop inside a mounted() function with nuxt.js. The data I tried to loop through was called with axios in created() but when I log the data in created() I get this object:
[__ob__: Observer]
mounted:
mounted() {
// creating FeaturedCasinos
for(let i = 0; i > this.casinos.length; i++) {
console.log("loop")
if(this.casinos[i].brand_tags[2].Brand_Tag_Name = "Featured") {
this.featuredCasinos.push(this.casinos[i]);
}
}
},
created:
created() {
return axios.get("http://xxx.xxx.xxx.xx/casinos/").then(res2 => (this.casinos = res2.data))
}
EDIT:
asyncData({ params }) {
return axios.get(casinoURL + params.casinos).then(res => {
return {
casino: res.data,
casinoID: res.data[0].id,
casinoBonus: res.data[0].bonuses,
casinoPros: res.data[0].brand_pros,
casinoCons: res.data[0].brand_cons,
casinoGames: res.data[0].verticals,
casinoTags: res.data[0].brand_tags,
casinoPayments: res.data[0].payment_methods,
casinoDeposits: res.data[0].Deposit_Methods,
casinoWithdrawals: res.data[0].Withdrawal_Methods,
casinoLanguages: res.data[0].languages,
casinoGamingProvider: res.data[0].gaming_provider,
casinoAnswers: res.data.map(item => { return {FAQ_Answer_One:item.FAQ_Answer_One, FAQ_Answer_Two:item.FAQ_Answer_Two, FAQ_Answer_Three:item.FAQ_Answer_Three, FAQ_Answer_Four:item.FAQ_Answer_Four, FAQ_Answer_Five:item.FAQ_Answer_Five, FAQ_Answer_Six:item.FAQ_Answer_Six}})
};
})
},
asyncData({ params }) {
return axios.get("http://xxx.xxx.xxx.xx/casinos/").then(res2 => {
return { casinos: res2.data }
});
},
As per the documentation:
You do NOT have access to the component instance through this inside asyncData because it is called before initializing the component.
So instead in asyncData you should return the data that will be merged with the component data as an object:
asyncData({ params }) {
return axios.get("http://xxx.xxx.xxx.xx/casinos/").then(res2 => {
return { casinos: res2.data }
}
}
EDIT: in this new case after you edited the question you should delete one of the asyncData and retrieve the unified data. You may use the async/await syntax to make the code more clear and easier to read:
asyncData({ params }) {
const res = await axios.get(casinoURL + params.casinos)
const res2 = await axios.get("http://xxx.xxx.xxx.xx/casinos/")
return {
casino: res.data,
casinoID: res.data[0].id,
casinoBonus: res.data[0].bonuses,
casinoPros: res.data[0].brand_pros,
casinoCons: res.data[0].brand_cons,
casinoGames: res.data[0].verticals,
casinoTags: res.data[0].brand_tags,
casinoPayments: res.data[0].payment_methods,
casinoDeposits: res.data[0].Deposit_Methods,
casinoWithdrawals: res.data[0].Withdrawal_Methods,
casinoLanguages: res.data[0].languages,
casinoGamingProvider: res.data[0].gaming_provider,
casinoAnswers: res.data.map(item => { return {FAQ_Answer_One:item.FAQ_Answer_One, FAQ_Answer_Two:item.FAQ_Answer_Two, FAQ_Answer_Three:item.FAQ_Answer_Three, FAQ_Answer_Four:item.FAQ_Answer_Four, FAQ_Answer_Five:item.FAQ_Answer_Five, FAQ_Answer_Six:item.FAQ_Answer_Six}})
casinos: res2.data
}
}

why componentdidmount called two times

I have React Component in componentDidMount fetch data from the server. The issue is componentDidMount called twice also the API called twice. I have a view increment API like youtube video views increment twice in the database because of twice API calling.
class SingleVideoPlay extends React.Component {
constructor(props) {
super(props);
this.player = React.createRef();
}
state = {
autoPlay: true,
relatedVideos: [],
video: null,
user: null,
comments: [],
commentInput: {
value: '',
touch: false,
error: false
},
following: false,
tab: 'comments'
};
_Mounted = false;
componentDidMount() {
this._Mounted = true;
if (this._Mounted) {
const videoId = this.props.match.params.id;
this.getVideoDetails(videoId);
}
}
componentWillUnmount() {
this._Mounted = false;
try {
clearInterval(this.state.videoInterval);
this.props.videoEditUrl('');
} catch (error) {}
}
captureVideoTime = async () => {
const { video } = this.state;
const result = await updateWatchTime({
id: video._id,
time: 1
});
if (result.status === 200) {
const updateVideo = {
...video,
secondsWatched: video.secondsWatched + 1
};
this.setState({ video: updateVideo });
}
};
videoEnded = () => {
clearInterval(this.state.videoInterval);
};
videoPause = () => {
clearInterval(this.state.videoInterval);
};
loadVideo = () => {
clearInterval(this.state.videoInterval);
};
playingVideo = () => {
const interval = setInterval(this.captureVideoTime, 1000);
this.setState({ videoInterval: interval });
};
getVideoDetails = async (videoId) => {
const video = await getVideo(videoId);
if (video.status === 200) {
let response = video.data;
if (this.props.userId)
if (response.user._id === this.props.userId._id)
this.props.videoEditUrl(`/video/edit/${response.media._id}`);
this.setState({
relatedVideos: response.videos.docs,
video: response.media,
user: response.user
});
this.checkIsFollowing();
this.updateVideoStat(response.media._id);
}
};
updateVideoStat = async (id) => videoView(id);
checkIsFollowing = async () => {
const { userId } = this.props;
const { video } = this.state;
if (userId && video) {
const response = await isFollow({
follower: userId._id,
following: video._id
});
if (response) {
this.setState({ following: response.following });
}
}
};
addOrRemoveFollowing = async () => {
this.checkIsFollowing();
const { following, video } = this.state;
const { userId } = this.props;
if (userId) {
if (following) {
const response = await removeFollow({
follower: userId._id,
following: video._id
});
this.setState({ following: false });
} else {
const response = await addFollow({
follower: userId._id,
following: video._id
});
this.setState({ following: true });
}
}
};
submitCommentHandler = async (event) => {
const { userId } = this.props;
event.preventDefault();
if (userId) {
const result = await saveComment({
mediaId: this.state.video._id,
parentId: '0',
userID: userId._id,
userName: userId.username,
comment: this.state.commentInput.value
});
console.log(result);
if (result.status === 200) {
this.getVideoComments();
this.setState({ commentInput: { value: '', touch: false, error: false } });
}
}
};
render() {
const { autoPlay, relatedVideos, video, user, comments, commentInput, following, tab } = this.state;
const { userId } = this.props;
return (
<div className="container-fluid">
some coponents
</div>
);
}
}
const mapStateToProps = (state) => ({
userId: state.auth.user
});
export default connect(mapStateToProps, { videoEditUrl })(SingleVideoPlay);
I don't know why componentDidMount called two times alse it shows memmory lecage issue.
How to Fix it.
Multiple componentDidMount calls may be caused by using <React.StrictMode> around your component. After removing it double calls are gone.
This is intended behavior to help detect unexpected side effects. You can read more about it in the docs. It happens only in development environment, while in production componentDidMount is called only once even with <React.StrictMode>.
This was tested with React 18.1.0
I think the issue exists on the parent component that used SingleVideoPlay component. Probably that parent component caused SingleVideoPlay component rendered more than once.
Also, there is an issue on your code.
componentDidMount() {
this._Mounted = true;
if (this._Mounted) {
const videoId = this.props.match.params.id;
this.getVideoDetails(videoId);
}
}
Here, no need to check if this._Mounted, because it will always be true.
1.Install jQuery by
npm i jquery
import $ from 'jquery'
create your function or jwuery code after the export command or put at the end of the file

Getting backend data in front reactJS

I am getting data from the backend to display it in the font like this
componentDidMount() {
const response = this.props.store.privateImputationData;
console.log(response);
}
It displays null in the console, now if i do a setTimeout it works!
componentDidMount() {
setTimeOut(() => {
const response = this.props.store.privateImputationData;
console.log(response);
}, 500);
}
This how i m getting data from my store:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.privateImputationData = result;
this.loadAdditionalData();
});
}
How can i do it without setTimeout?
You can use the state object: State and Lifecycle. Whenever the state changes, whatever component uses it, get's updated too.
this.state = {privateImputationData: null} //or some default
So in your code:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.setState({privateImputationData: result});
this.loadAdditionalData();
});
}
To use the value:
this.state.privateImputationData;

Handling multiple ajax requests, only do the last request

I'm doing a project that fetch different types of data from SWAPI API (people, planets, etc.) using react but I have an issue with multiple Ajax request.
The problem is when I quickly request from 2 different URL for example, 'species' and 'people', and my last request is 'species' but the load time of 'people' is longer, I will get 'people' instead.
What I want is to get the data of the last clicked request, if that make sense.
How do I achieve that? All the solution I found from Google is using jQuery.
Here's a slice of my code in src/app.js (root element) :
constructor(){
super();
this.state = {
searchfield: '',
data: [],
active: 'people'
}
}
componentDidMount() {
this.getData();
}
componentDidUpdate(prevProps, prevState) {
if(this.state.active !== prevState.active) {
this.getData();
}
}
getData = async function() {
console.log(this.state.active);
this.setState({ data: [] });
let resp = await fetch(`https://swapi.co/api/${this.state.active}/`);
let data = await resp.json();
let results = data.results;
if(data.next !== null) {
do {
let nextResp = await fetch(data.next);
data = await nextResp.json();
let nextResults = data.results
results.push(nextResults);
results = results.reduce(function (a, b) { return a.concat(b) }, []);
} while (data.next);
}
this.setState({ data: results});
}
categoryChange = (e) => {
this.setState({ active: e.target.getAttribute('data-category') });
}
render() {
return (
<Header searchChange={this.searchChange} categoryChange={this.categoryChange}/>
);
}
I made a gif of the problem here.
Sorry for the bad formatting, I'm writing this on my phone.
You have to store your requests somewhere and to abandon old ones by making only one request active. Something like:
getData = async function() {
console.log(this.state.active);
this.setState({ data: [] });
// my code starts here
if (this.controller) { controller.abort() }
this.controller = new AbortController();
var signal = controller.signal;
let resp = await fetch(`https://swapi.co/api/${this.state.active}/`, { signal });
let data = await resp.json();
let results = data.results;
if(data.next !== null) {
do {
let nextResp = await fetch(data.next);
data = await nextResp.json();
let nextResults = data.results
results.push(nextResults);
results = results.reduce(function (a, b) { return a.concat(b) }, []);
} while (data.next);
}
this.setState({ data: results});
}

stampit.js beginner needs some guidance

I'm implementing service between a view and a Rest API.
Beside, i'm completly new to stamp programming and i'm in search of some advices about this sort of code:
import {compose, methods} from '#stamp/it'
import ArgOverProp from '#stamp/arg-over-prop'
import {template} from 'lodash'
const createLogger = name => (...args) => console.log('['+ name + ']', ...args)
const HasHttpClient = ArgOverProp.argOverProp('httpClient')
const HasApiVersion = ArgOverProp.argOverProp('apiVersion')
const HasUrl = ArgOverProp.argOverProp('url')
const UseRestApi = compose(HasHttpClient, HasApiVersion, HasUrl).init([
function () {
this.getUrl = template(this.url)
this.useRestApiLog = createLogger('UseRestApi')
}
]).methods({
query: function query(method, {params, headers, body}) {
const {apiVersion} = this
const q = {
baseURL: this.getUrl({apiVersion}),
method,
...params != null && {params},
...headers != null && {headers},
...body != null && {body}
}
this.useRestApiLog('request config:', q)
return q
}
})
const WithGetOperation = compose(UseRestApi).init([
function () {
this.withGetOperationLog = createLogger('WithGetOperation')
}
]).methods({
'get': function get ({params}) {
const q = this.query('get', {headers: {'Accept': 'application/json'}, params})
this.withGetOperationLog('getting data')
return this.httpClient(q)
}
})
const CustomerRestApi = compose(WithGetOperation).init([
function () {
this.customerRestApiLog = createLogger('CustomerRestApi')
}
]).methods({
all: function all() {
this.customerRestApiLog('get all customers')
return this.get({params: {page: 1, limit: 15}})
}
})
const customerProvider = CustomerRestApi({
url: 'http://sample.com/<%=apiVersion%>/customers',
apiVersion: 'v1',
httpClient: function(config) {
return Promise.resolve({
status: 200,
config
})
}
})
const appLog = createLogger('APP')
customerProvider.all()
.then(r => appLog('HTTP response code:', r.status))
Am i in the right directions?
Especially, the createLogger thing seems ugly!
How to inject a prefixed logger into each stamp ?
How to extend that to warn, error, ... methods ?
Your logger looks just fine. 👍 It is not necessary to create every bit as a stamp. However, if you want to make the logger as a reusable stamp then you can do the same way as ArgOverProp is implemented.
Ruffly ArgOverProp is done this way:
const ArgOverProp = stampit.statics({
argOverProp(...args) {
return this.deepConf({ArgOverProp: [...args]});
}
})
.init(function (options, {stamp}) {
const {ArgOverProp} = stamp.compose.deepConfiguration;
for (let assignableArgName of ArgOverProp) {
this[assignableArgName] = options[assignableArgName];
}
});
Your logger could look like this (not necessary exactly like this):
import {argOverProp} from '#stamp/arg-over-prop';
const Logger = stampit(
argOverProp('prefix'),
{
methods: {
log(...args){ console.log(this.prefix, ...args); },
error(...args){ console.error(this.prefix, ...args); },
warn(...args){ console.warn(this.prefix, ...args); }
}
}
);
const HasLogger = stampit.statics({
hasLogger(name) {
return this.conf({HasLogger: {name}});
}
})
.init(_, {stamp}) {
const {HasLogger} = stamp.compose.configuration;
if (HasLogger) {
this.logger = Logger({prefix: HasLogger.name});
}
});
And usage:
const CustomerRestApi = stampit(
WithGetOperation,
HasLogger.hasLogger('CustomerRestApi'),
{
methods: {
all() {
this.logger.log('get all customers');
return this.get({params: {page: 1, limit: 15}});
}
}
);
I always prefer readability. So, the code above, I hope, is readable to you and any stampit newbie.
PS: a tip. The stampit and the stampit.compose you imported above are the same exact function. :) See source code.

Categories

Resources