MooTools - Re-use Request Object - mootools

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/

Related

DataVizExtention: issue with clearing viewables while a sprite is selected

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 🙂

Changing materials in Forge

We are currently making the client retrieve the object states when the page loads (which will cause the 'pending' objects in the model to turn into different colors). Then we poll for changes to update the coloring (Firstly: pending object gets colored when the viewer loads, and then we keep polling to check and change state again, to make Forge render those in a different color and store their old color/material. When the polling received a change that an object should no longer be colored, it tells Forge to use the old color/material again.
The problem:
We've found out what the problem is, but we couldn't find out how to fix it. The problem is that changing materials in Forge doesn't work after startup anymore, it only works in the first ~3 seconds or so (the materials were used to show the colors).
However, setting overlays works even after the first ~3 seconds, (showing overlays instead of materials to show the colors).
This is not what we want to achieve. This looks unoptimized, because overlays will be shown through everything.
The materials, however, seem to be 'locked', as in, they cannot be changed anymore after the first ~3 seconds. It seems like they aren't refreshed or something
In the examples, we found they used viewer.impl.invalidate(true) to refresh the Forge viewer, but that doesn't do anything after ~3 seconds.
We've also tried every combination of viewer.impl.invalidate(true, true, true) as well as setting material.needsUpdate to true, as well as trying to re-render the entire scene.
We also found this: https://github.com/mrdoob/three.js/issues/790, but we couldn't find a good way to do that in Forge, we tried viewer.requestSilentRender() but that didn't do anything either.
Anyway, we've tried everything we could come up with and could find online to make the materials work, but nothing made a difference.
We are looking to find someone that's more experienced with how Forge works that can see what the material code is doing wrong.
As for the content, here is all the code you will need to understand what is happening:
DROPBOX LINK
And here is a small part of the "index.html" file that sets the color:
try
{
viewer.restoreAllColorOverlays(); //for materials instead of overlays: viewer.restoreAllColorMaterials();
$.each(colors, function(color, selectionIds)
{
viewer.setColorOverlay(selectionIds, color); //for materials instead of overlays: viewer.setColorMaterial(selectionIds, color);
});
}
catch(error)
{
console.error(error);
}
I have no idea how you implement your app, so I only tell what I found in your codes. If you want to resolve the issue you addressed, you can consider providing a reproducible case demonstrating that, I will gladly pass it to our dev team. Those following items should be in the reproducible case:
A short exact description of what you are trying to achieve. The behavior you observe versus what you expect, and why this is a problem.
A complete yet minimal sample source model to run a test in.
A complete yet minimal Forge app that can be run and debugged with a simple procedure to analyze its behavior lives in the sample model.
A complete yet minimal pure three.js app that can be run and demonstrated the shader effect you want. Note. Forge Viewer is using r71 three.js.
Detailed step-by-step instructions for reproducing the issue, e.g. which element to pick, what command to launch etc.
If your reproducible case could not be posted here publicly, please send it to the forge.help#autodesk.com and remove sensitive data or information before you send.
=== Something I found in your codes:
I found here are some wrong types and missing actions in your ColorMaterial extension. The color property of an material should the a type of the THREE.Color. Here is my modification:
Autodesk.Viewing.Viewer3D.prototype.setColorMaterial = function(objectIds, color)
{
if( !(color instanceof THREE.Color) ) throw 'Invalid argument: Color';
var material = new THREE.MeshPhongMaterial
({
color: color,
opacity: 0.8,
transparent: true
});
viewer.impl.matman().addMaterial( 'ColorMaterial-' + new Date().getTime(), material, true );
// ...........
};
Its' result is here:
In the ColorOverlay extension, The type of material color property is also wrong, it should be a type of THREE.Color, too. Changing it into THREE.Color should work fine. In addition, overlay is covers on 3D objects, so you should call viewer.hide() with your setColorOverlay() together. Otherwise, it won't look like a transparent object.
Without hidding 3D object of the wall:
hide 3D object of the wall:

React-Router - componentDidMount not called when navigating to URL

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.

How to extend a native mootools method

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.

Losing my mind from jquery validate and knockout

I have been trying to do this for months, and months, and months, and
months. And I am literally at the point of tears from trying to get Knockout to work for me.
I have posts dating back way last year trying to do this. I
just simply cannot get validation to work with knockout and asp.net
mvc.
If I put the $.validator.unobtrusive.parse("#__frmAspect"); line in, I
get the validation, but then it does not obey the submit handler. If I
take that out, it obeys the submit handler, but it does not get any
validation.
This is my code - all of it. (I think)
Main View
http://pastie.org/2016031
Editor View
http://pastie.org/2016043
View Model
http://pastie.org/2016045
Controller and Model Binder
http://pastie.org/2016052
Html Output
http://pastie.org/2016100
HtmlTags class
http://pastie.org/2016107
Helpers
http://pastie.org/2016111
I have been stuck on this for literally going on 8 months. Can anyone
please help me? All I want is to submit the data back to the server. I
don't want ajax, I don't want a callback. I don't want anything fancy.
I just want to send my JSON model back to the server after proper
client validation, and have it get the data. That is all I want. I do
not want to use the $.ajax method. I have reasons for why I want to do
it this way, and they are not relevant to the question.
Response to RP Niemeyer
Yes, that worked!!!!!!!! oh my god. I owe you like ,the last 8 months
of my life. I want to send you a cheesecake smothered in raw calories
of taste and internets.
I feel like I could punch the screen from how frustrated this problem
made me. I'm sorry if the question sounded rude, but no where on the
internet have I seen this kind of thing. I'm sure any other developer
can understand the frustration of a problem that just does not seem to
have an answer.
I have no idea how you came to this conclusion and I don't understand
exactly why it worked.
I tried the same thing with an object-instanced view model (where the
view model was not its own object, but an instance of another object)
and it didn't work. In other words, if I do ..
var aspect = function () {
this.Id = ko.observable();
// other variables, using ';' and 'this' keyword
this.Save = function() {
alert('We got to the save function');
}
}
var viewModel = new aspect();
ko.applyBindings(viewModel, $("#__frmAspect")[0]);
// attach the jquery unobtrusive validator
$.validator.unobtrusive.parse("#__frmAspect");
// bind the submit handler to unobtrusive validation.
$("#__frmAspect").data("validator").settings.submitHandler =
viewModel.Save;
This approach did not work.
Can I bother you to explain to me what is different, and why? I am
completely lost.
I think that the issue is that the unobtrusive library will have already setup validation on the form, so you would actually need to go in and set the submitHandler like:
// attach the jquery unobtrusive validator
$.validator.unobtrusive.parse("#__frmAspect");
// bind the submit handler to unobtrusive validation.
$("#__frmAspect").data("validator").settings.submitHandler = viewModel.Save;
http://jsfiddle.net/rniemeyer/V8MhG/