I'm a little stumped on this one. I defined a route called classes/:id. When navigating to that route in the app, the componentDidMount() is called. However, when reloading the page or copying and pasting the URL the page completely loads, but the componentDidMount() method is not called at all.
From what I have read, the reason is because the same component mounted even though the page is being reloaded which is why the lifecycle method does ever get fired off.
What are some ways to handle this? Your help is greatly appreciated. Thanks!
componentDidMount will not be called again if you are already at a classes/:id route. You'll probably want to do something along the lines of:
componentDidUpdate(prevProps) {
if (this.props.id !== prevProps.id) {
// fetch or other component tasks necessary for rendering
}
}
I try to avoid any mixins (see willTransitionTo), as they are considered harmful.
Although componentDidMount does not fire when changing routes for the same component, componentWillUpdate and componentWillReceiveProps do.
From there, you can detect parameter changes, and can fire your actions accordingly.
the componentWillReceiveProps,componentDidUpdate lifecycle will receive the new props and then setState to change state to trigger render method.
I just dealt with this exact issue, took me a while to figure out the problem. I'm sure everything previously suggested works great as a solution. How I solved the problem was a bit different though. My componentDidMount function was essentially just providing a state update, so I just moved the functionality directly into the state and bypassed componentDidMount.
Honestly, I'm not sure if this is best practice or not (very happy for feedback if it isn't), but it's running efficiently and works great so far.
Related
Line within render() :
<div class={{ 'modal-backdrop show': this.show, 'modal-backdrop hide': !this.show }}>
Test :
it('should display correctly', async () => {
const page = await newE2EPage();
await page.setContent('<my-component></my-component>');
let element = await page.find('my-component');
expect(element).not.toBeNull();
element = await page.find('div.modal-backdrop.hide');
expect(element).not.toBeNull();
});
Description of the issue:
I have provided only a part of the code and unfortunately I cannot provide much more due to confidentiality. However I will do my best to describe the issue. There are two components in the project, tests for component A work as they should. Tests for component B (provided above) do not. While the first expect passes, the second one fails due to it being null but it shouldn't.
A few facts:
The project can be built, run and used without a problem.
Unit tests work as intended, including tests for the render() method.
The code in it-self is not wrong, I have tested, retested and tested again and it works for other components but not for this one.
Although the default is .hide, I have tried with both .hide and .show, neither work.
Best guess so far:
I have had many issues getting the tests to work due to how the code is written. While running tests many objects where undefined and that was causing the tests to fail. From everything that I tried and tested my best theory is that for some reason this component half fails in the context of the puppeteer browser, making the core object but nothing else. I don't know if that is possible but it looks like that.
Web components use their own document tree called shadowDOM, which isn't visible from the main DOM (page); thus your page.find fails. This concept is called encapsulation. Btw, I wasn't able to find a method called find on the page object in Puppeteer's documentation; can you explain where it comes from?
To access the shadow tree inside a web component, you'll have to access it using element.shadowRoot:
element = await page.find('my-component');
expect(element.shadowRoot.querySelector('div.modal-backdrop.hide')).not.toBeNull();
There's puppeteer addons and applications which can help with that:
https://github.com/PavelDymkov/puppeteer-shadow-selector
https://docs.puppetry.app/testing-techniques/testing-shadow-dom
To find more, check https://www.google.com/search?q=puppeteer+shadow+DOM.
In my code, I have this workflow:
When user wants to see some things, add Sprites using 'DataVizCore.addViewables()'
Use 'viewer.addEventListener(DataVizCore.MOUSE_CLICK, onDotClick)' to show info bubble
When user wants to show other things, call 'DataVizCore.removeAllViewables()' to clear Sprites
Repeat from step 1
This sequence works OK except in one situation.
If a sprite was selected (by clicking on it) before removeAllViewables() is called, I don't get MOUSE_CLICK event for newly added Sprites. In browser console, I see following error is thrown.
CustomViewables.js:318 Uncaught TypeError: Cannot read property 'style' of undefined at ViewableData.getViewableUV (developer.api.autodesk.com/modelderivative/v2/viewers/7.*/extensions/DataVisualization/DataVisualization.js:454)
As a workaround, I added 'event.hasStopped = true' to click event handler to prevent Sprite getting selected internally. That seems to work.
This seems like a bug in DataVizExtension to me. Or, my workflow is wrong?
Thanks
Bandu
Bandu. Thanks for the detailed steps to reproduce this issue. I tried with v7.46.0 version of the DataVisualization.js (latest as of my message) but was not seeing the same issue. I'd be curious if you are using this same version of the Forge Viewer (you can figure that out by looking at the viewer3D.js fetched under the Network tab of Chrome DevTools).
Setting event.hasStopped = true works because it internally avoided the code path calls into getViewableUV that threw the exception, but the flag is meant for other use cases (e.g. overriding default sprite selection behavior).
In any case, I've just tweaked our internal code to make use-cases like yours more robust. The changes will be released with the upcoming v7.47.0. Thank you for your feedback 🙂
I receive data in a function and this function needs to load a new page. I was doing this with Jquery using the method .load(), But my vue method gets an error saying that can not find the element in the other page.I believe that could be a better approach, but I do not know how I can pass data through a vue component
static foo(a,b){
$('#maindiv').load("/newPage");
new Vue({
el: '#newPageElem',
data: {
vueVar1:a
vueVar2:b
},
});
}
How can I do that? I believe that using Jquery is not the best way to achieve this, but I dont know how to change routes with vue and passing parameter between them.
Thanks.
You can take a look at vue-router here: http://router.vuejs.org/en/essentials/getting-started.html - it allows you to handle all the client-side routes.
For making http calls to receive data from server, you can use vue-resource (https://github.com/vuejs/vue-resource)
It is better to avoid mixing jQuery with Vue, as Vue is responsible for rendering the DOM. If you make any DOM changes with jQuery, it will get over-written by Vue in the next DOM update. So you will end up spending a lot of time in debugging.
Also, you cannot instantiate a Vue app inside a function, as seen in your code example, unless you call the function on page load. Ideally, the first few lines of script should start the Vue app.
Is it possible to extend the addEvent function in mootools to do something and also calls the normal addEvent method? Or if someone has a better way to do what I need I'm all years.
I have different 'click' handlers depending on which page I'm on the site. Also, there might be more than one on each page. I want to have every click on the page execute a piece of code, besides doing whatever that click listener will do. Adding that two lines on each of the handlers, would be a PITA to say the least, so I thought about overriding the addEvent that every time I add a 'click' listener it will create a new function executing the code and then calling the function.
Any idea how I could do it?
Whereas this is not impossible, it's a questionable practice--changing mootools internal apis. Unless you are well versed with mootools and follow dev direction on github and know your change won't break future compatibility, I would recommend against it.
The way I see it, you have two routes:
make a new Element method via implement that does your logic. eg: Element.addMyEvent that does your thing, then calls the normal element.addEvent after. this is preferable and has no real adverse effects (see above)
change the prototype directly. means you don't get to refactor any code and it will just work. this can mean others that get to work with your code will have difficulties following it as well as difficulties tracing/troubleshooting- think, somebody who knows mootools and the standard addEvent behaviour won't even think to check the prototypes if they get problems.
mootools 2.0 coming will likely INVALIDATE method 2 above if mootools moves away from Element.prototype modification in favour of a wrapper (for compatibility with other frameworks). Go back to method 1 :)
I think solution 1 is better and obvious.
as for 2: http://jsfiddle.net/dimitar/aTukP/
(function() {
// setup a proxy via the Element prototype.
var oldProto = Element.prototype.addEvent;
// you really need [Element, Document, Window] but this is fine.
Element.prototype.addEvent = function(type, fn, internal){
console.log("added " + type, this); // add new logic here. 'this' == element.
oldProto.apply(this, arguments);
};
})();
document.id("foo").addEvent("click", function(e) {
e.stop();
console.log("clicked");
console.log(e);
});
it is that simple. keep in mind Element.events also should go to document and window. also, this won't change the Events class mixin, for that you need to refactor Events.addEvent instead.
I would like to re-use a Request.JSON object, but I am not sure how. I'm looking for something like the following example:
// In initialize/constructor
this.request = new Request.JSON( {
method : 'get'
});
// Elsewhere
this.request.setOptions({
url : 'http://...',
onSuccess : onSuccess,
onFailure : onFailure
}).send();
there are going to be certain issues with this kind of approach.
if you only have the one instance handling all requests, then you need to make sure whilst a request is taking place, there is nothing else that can restart it with the new options as its asynchronous. additionally, events will stack up. every new instance that you run will addEvent onComplete/onSuccess/onFailure and they won't always be relevant. so you need to apply removeEvents() to the request instance before each run.
have a look here http://www.jsfiddle.net/dimitar/8a7LG/4/
i am not showing this as an example of how i'd write it but to see the problems that come with it. click the second link first then the first one (jsfiddle adds 2 seconds network lag) and you will see the alert from the second link's onComplete event stacked up on the first one as well. further more, for each click on link 2 you will see a new alert in addition to the old ones.
you must also consider how applicable it is to extend Request.JSON instead but it all depends on your needs.
p.s. if you go over to Request.JSONP this kind of structure may play some tricks, in particular with the callback functions being reset etc.
best of luck :)
edit here's the thing working with removeEvents so you don't get the stacking up: http://www.jsfiddle.net/dimitar/8a7LG/5/
I don't differ with the accepted answer's point, but it actually sidesteps the question IMHO.
Take a look at the following blog post (it's not mine); there, under the subtitle Multiple Links with Request.HTML you can find some guidance about how to reuse the Request instance.
http://ryanflorence.com/basic-ajax-and-json-requests-with-mootools/