Metamask complaining about synchronous method even with callback parameter - web3

I'm getting a
The MetaMask Web3 object does not support synchronous methods like eth_gasPrice without a callback parameter.
even though I'm providing that callback parameter:
web3.eth.gasPrice((err, gasPrice) => {
if (err) {
console.log(err)
} else {
store.dispatch('pollWeb3', {gasPrice: gasPrice})
}
})
According to the doc this should be working. Am I mistaken?

The moment I submit the question...
If used with a callback, the method name must be web3.eth.getGasPrice(...

Related

Consuming IMDB api results bad json

I have a simple program that consumes IMDB api, I'm getting the result, but it was shown as error because the result is not a structured json.
MovieService.ts
export class MovieService {
constructor(private http:HttpClient) { }
getMovie(movie:string){
return this.http.get(this.generateURL(movie));
}
private generateURL(movie:string){
return "https://v2.sg.media-imdb.com/suggests/titles/"+movie.charAt(0)+"/"+movie+".json?callback=imdb$"+movie;
}
}
addmovie.component.ts
private _filterMovies(value: string) {
this.movieService.getMovie(value).subscribe(
movies => {
console.log(movies);
return movies;
}
);
}
ngOnInit() {
this.addMovieForm.get('movie').valueChanges.subscribe(val => {
this._filterMovies(val)
});
}
I'm getting error like
the response is of bad json. How can I format the json upon receiving? How to solve this? Any leads would be helpful.
The result is not JSON, but rather JSONP. It is essentially returning you a script that is trying to execute the callback method specified.
Instead of http.get() you should call http.jsonp(url, "imbdIgnoresThisParam").
However, according to this answer, the callback query string parameter is ignored by IMDB. The answer suggests dynamically creating the expected callback function, whose name contains the title for which you are searching. In that callback you could do a few different things.
Use the closure to call / set something in your MovieService. This will result in your call to the API throwing an error, as the Angular framework's callback will not be called as expect. You could ignore the error.
Try to call the expected Angular callback, ng_jsonp_callback_<idx>. This will prevent the API call from throwing, but it may not be reliable. The callback name is dynamic and increments with each jsonp() call. You could try to track the number of jsonp() calls in your app. And of course, the framework may change and break this solution. Concurrent calls to getMovie() may break, as the next one may step on the previous callback on the window. Use with caution!
In typescript, your getMovie() function and related helpers might look like so:
private imdbData: any = null;
private jsonpIdx = 0;
private setImdb(json: any) {
this.imdbData = json;
// or do whatever you need with this
}
getMovie(movie:string) {
// dynamically create the callback on the window.
let funcName = `imdb$${movie}`;
window[funcName] = (json: any) => {
// use the closure
this.setImdbData(json);
// or try to call the callback that Angular is expecting.
window[`ng_jsonp_callback_${this.jsonpIdx++}`](json);
}
// go get your data!
let url = this.generateURL(movie)
return this.http.jsonp(url, "ignored").subscribe((json) => {
// this happens if you successfully trigger the angular callback
console.log(json);
}, (err) => {
// this happens if the angular callback isn't called
console.log(this.imdbData); // set in closure!
});
}
Edit for Angular 4
For Angular 4, it looks like you will need to import the JsonpModule along with the HttpModule. Then, you'd inject jsonp just like you'd inject http into your service. The call to IMDB becomes this.jsop.request(url).subscribe(...) and your dynamic callback name needs to change, too.
window[funcName] = (json: any) => {
// or try to call the callback that Angular is expecting.
window["__ng_jsonp__"][`__req${this.jsonpIdx++}`]["finished"](json);
}
I don't have an Angular 5 or 6 project immediately set up, so hard to say if there are any differences with the callback in those versions.
Sort of a hack, but hope it helps!

How should I parse this json object in react with lifecycle method?

How should I parse this using lifecycle methods?
{"blocks":[{
"key":"33du7",
"text":"Hello there!",
"type":"unstyled",
"depth":0,
"inlineStyleRanges":[],
"entityRanges":[],
"data":{}}],
"entityMap":{}
}
I want to render the text in my component but I don't know why it throws undefined error. How should I call it?
This is my component:
class Blog extends Component{
constructor(props){
super(props);
this.blogContent = props.blogContent;
this.blogId = props.blogId;
this.handleRemoveBlog = this.handleRemoveBlog.bind(this);
this.state = {
blog__: '',
};
}
handleRemoveBlog(blogId){
this.props.removeBlog(blogId);
}
This is my lifecycle method , I would use this.setState but first of all it's giving undefined in console.
componentWillMount(){
this.state.blog__ = JSON.parse(this.blogContent);
console.log(this.state.blog__.text); // this gives undefined
}
This is the render part..
The data is coming from Firebase.
And {this.blogcontent} gives that json string that I previously mentioned.
render(props) {
return(
<div className = "blog header">
<p>{this.blog__.text}</p>
</div>
);
}
}
Blog.proptypes = {
blogContent: Proptypes.string
}
This would mostly depend on where you are getting this object from. If it is fetched over the network then the best place to pass it is in the componentDidMount. The reason for this is that the alternative lifecyle method (componentWillMount) does not guarantee a re-render of your component since it does not wait for async actions to finish execution before passing control down to your render method. Hence componentDidMount is best because as soon as new props are received or state is changed it will trigger a re-render. However, if this object is pulled from within the application then chances are, it will work just fine even if pulled within componentWillMount. This is because that operation would be much quicker, so much that control would be passed down to the render method with the new props. This is not guaranteed especially if you want to set state in the process (setting state is also async, so control might execute the rest of the code before all the required data is received).
In short, pass this to componentDidMount and in your render function, before accessing this prop, make sure that it exists. That is, instead of
render() {
return <div>{this.props.theObject.blocks[0].key}</div>
}
rather do:
render() {
return <div>{this.props.theObject && this.props.theObject.blocks[0].key}</div>
}
This is how you would do it (assuming you are getting the file over the network using axios)
componentDidMount() {
axios.get('url/to/the/file')
.then(fileData => this.setState({
data: fileData
});
}
render() {
// return whatever you want here and setting the inner html to what the state holds
}
You should not modify the state using
this.state.blog__ = JSON.parse(this.blogContent);
The proper way to do it is using the this.setState() method:
this.setState({blog__: JSON.parse(this.blogContent)})
Then, to ensure that the component will be re-rendered, use the method shouldComponentUpdate():
shouldComponentUpdate(nextProps,nextState) {
if(nextState != this.state) {
this.forceUpdate()
}
}
Take a look at the State and Lifecycle docs.
Other point: Use componentDidMount() instead of componentWillMount(), because it will get deprecated in the future.
Atention: The setState() is an asynchronous method. So, it won't instant update your state.
Use this.setState({}) in your componentWillMount function instead assign the data to the variable. Also I recommend to use componentDidMount instead of componentWillMount because it's getting deprecated in the future.
componentDidMount(){
let text = JSON.parse( this.blogContent );
this.setState({blog__: text });
}
Edit: Only use setState in componentDidMount according to #brandNew comment

How to detect a transaction that will fail in web3js

I've just recently finished working on a rather complex contract with the Remix IDE. I'm now attaching web3 to the frontend but when I call functions that should fail, they still go through on Metamask.
When testing my contract in Remix, I would often click on and call certain functions that had require statements that I knew would fail just to confirm that the contract state was recorded correctly. Remix didn't send the transaction to metamask and instead output an error message and I would like to handle the transaction error on my own as well.
How can I check my contract call to see whether it will fail. Must I use the method that predicts gas and detect it that way and if so how? My current code is below:
contract.callFunction(function(error, result) {
if (!error) alert(result);
else alert(error);
}
The above code catches rejecting the metamask confirmation as an error but transactions that should fail go through to metamask with an insanely high gas limit set. The function callFunction is in the contract and takes no parameters but does have an effect on the blockchain so it requires the transaction. The first line of the function is "require(state == 1);" and I have the contract set to state 2 currently so I'm expecting the transaction to fail, I just want to detect it failing.
In order to find out whether the transaction will fail we do have to call estimateGas() and attach a callback function. I assumed we'd have to check the gas estimate returned in order to predict whether it would fail but the process is made rather easy. Here's the full code I ended up with to successfully run a function while catching the two most common error cases.
contract.nextState.estimateGas(function(error, result) {
if (!error) {
contract.nextState(function(error, result) {
if (!error) {
alert("This is my value: " + result);
} else {
if (error.message.indexOf("User denied") != -1) {
alert("You rejected the transaction on Metamask!");
} else {
alert(error);
}
}
});
} else {
alert("This function cannot be run at this time.");
}
});
[EDIT] I'm coming back after the fact to help clear up information for those with a similar question. All of the information discussed below references the following link.
After creating a contract object, you can access any variable or function through using it's name. You can also access these members through array notation which is useful when the name of the variable or function isn't known at the time the code is written.
contract.foobar == contract["foobar"]
Once you have a function object (contract.foobar) you can use either call, send, or estimateGas. After first giving the function the parameters it needs (call it like any other function) you then use either call, send, or estimateGas on the returned object while providing options and a callback function.
This callback function takes 2 parameters. The first is the error which will be undefined if there was no error, and the second will be the result of the call, send, or estimateGas. Call and Send will both return the result of the function while estimateGas always returns a number showing how much gas is estimated to be necessary.

Calling Jersey from Angular2

I'm beggining to play with Angular2. I have developed a basic RESTful API using Jersey. I tested it and it works fine (with browser and SOAP UI). This is the code:
#GET
#Produces(MediaType.APPLICATION_JSON)
public TwoWordsMessage getMessage() {
TwoWordsMessage message = new TwoWordsMessage();
message.setFirstWord("hello");
message.setSecondWord("world");
return message;
}
I'm tryng to call the service from an Angular2 app:
this.http.request(this.url).subscribe((res: Response) => {
this.message = res.json();
});
I can see (debbuging) that "getMessage" method is called and it returns the TwoWordsMessage object but the Angular2 application never gets it. The same code with the url http://jsonplaceholder.typicode.com/posts/1 works fine.
What I'm doing wrong?
Thanks!
Are you calling the http request inside a component or a service? Does a function or method fire off the http request?
Also, can you see if there are errors coming back from the response? The subscribe method can take three functions as parameters, first one being on success, second on error, third on completion. If there's an error in the AJAX call (400s, 500s, etc), your code would never be able to handle it. Try this:
this.http.request(this.url).subscribe((res: Response) => {
this.message = res.json();
}, (error) => {
console.warn(error)
});
and see what is spit out. To further debug, you can even use the .do() method on the Observable:
this.http.request(this.url)
.do((res: Response) => console.log(res)) // or other stuff
.subscribe((res: Response) => {
this.message = res.json();
});
The .do() method will execute an arbitrary function with the response without actually affecting it.
If not, you could also try changing the http call to http.get(). I don't think that's the problem, but the Angular docs do not state what method is defaulted to with http.request() (although I would be almost certain it's a GET).
I finally got it working. It's a CORS problem.
The console showed the error:
"No 'Access-Control-Allow-Origin' header is present on the requested
resource"
I changed the resource method like this:
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getMessage() {
TwoWordsMessage message = new TwoWordsMessage();
message.setFirstWord("hello");
message.setSecondWord("world");
return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(message).build();
}
You can find useful information here:
http://www.codingpedia.org/ama/how-to-add-cors-support-on-the-server-side-in-java-with-jersey/

why do i need 2 parameters for callback?

i have a simlple asynchronious reader in a node-script reading firefox-json-bookmarks.
when i remove the first parameter (err) in the callback function, i got an error.
what is the reason? And why is err different from e?
app.js
var fs = require('fs'), obj;
fs.readFile(__dirname + '/bookmarks.json', 'utf8', handleFile);
function handleFile( err, data ) { // why is the first parameter needed?
try {
obj = JSON.parse( JSON.stringify(data) );
console.log(obj);
} catch (e) {
console.log(e);
//console.log(err);
}
}
Each time you call a function, that function is pushed onto a stack of functions known as the call stack. When that function returns a value, it is popped off the stack. The call stack describes where you are in your program and how you got there.
Synchronous Code
Imagine the call stack through out the course of this program.
function a() { return b() }
function b() { return c() }
function c() { throw new Error() }
a();
First, a is called, so we add it to the stack.
[ a ]
Then a calls b, so we add that to the stack too.
[ a, b ]
Then b calls c.
[ a, b, c ]
Then c throws an error. At this point, the debugger can tell you that c was the function that threw the error and that you ended up at c, via a then b. This works fine for regular synchronous code, like JSON.parse.
Asynchronous Code
Asynchronous code continues to run after the function has returned. For instance:
function a() {
setTimeout(function() { console.log(2); }, 10000);
return 1;
}
If you call a, then it will be pushed onto the call stack, then return 1 and be popped off the call stack. About 10 seconds later 2 will be printed into the console.
What would happen if the timeout did this instead?
function a() {
setTimeout(function() { throw new Error(); }, 10000);
return 1;
}
The error would be thrown, but the call stack would be empty. As you can imagine, this isn't very useful for developers.
This is also a problem if we want to return a value asynchronously. By the time the async stuff happens (timeout, read/write, network etc), the function has already returned.
Instead, we can use a form of what's known as Continuation-Passing Style, mostly referred to as callbacks. As well as calling our asynchronous function, we also pass it function (a continuation), which we ask it to run when it has finished. Remember, this can be after the function has returned a value!
In Node.js, these callbacks serve two purposes:
Errors
If an error occurs whilst doing the asynchronous work, standard practice is to call the callback with the error as the first argument. You'll often see the following code.
foo.doAsyncBar(function(err, baz) {
if(err) throw err;
// do something with baz
});
By passing the error the callback rather than throwing it, we are able to make our own decisions about how best to handle it. We can just throw it, as shown above, or we can handle it in a more graceful way.
Return
Hopefully, the function won't error, in which case, the general practice is to pass null as the first argument to the callback. This lets the developer writing the handling code know that the function didn't error and that the return value is in one of the next arguments.
For a more in depth article on Node.js error handling, see Joyent's Production Practices document for Errors.