Subscribe is deprecated: Use an observer instead of an error callback - callback

When I run the linter it says:
subscribe is deprecated: Use an observer instead of an error callback
Code from this angular app:
this.userService.updateUser(data).pipe(
tap(() => {bla bla bla})
).subscribe(
this.handleUpdateResponse.bind(this),
this.handleError.bind(this)
);
Don't know exactly what should I use and how...
Thanks!

subscribe isn't deprecated, only the variant you're using is deprecated. In the future, subscribe will only take one argument: either the next handler (a function) or an observer object.
So in your case you should use:
.subscribe({
next: this.handleUpdateResponse.bind(this),
error: this.handleError.bind(this)
});
See these GitHub issues:
https://github.com/ReactiveX/rxjs/pull/4202
https://github.com/ReactiveX/rxjs/issues/4159

Maybe interesting to note that the observer Object can also (still) contain the complete() method and other, additional properties. Example:
.subscribe({
complete: () => { ... }, // completeHandler
error: () => { ... }, // errorHandler
next: () => { ... }, // nextHandler
someOtherProperty: 42
});
This way it is much easier to omit certain methods. With the old signature it was necessary to supply undefined and stick to the order of arguments. Now it's much clearer when for instance only supplying a next and complete handler.

For me, it was just the typescript version my VSCode was pointing to.
Got help from this GitHub comment.
I believe this is a typescript issue. Something in the newest versions of typescript is causing this warning to display in vs code. I was able to get it to go away by click the version of typescript in the bottom right corner of vs code and then choosing the select typescript version option. I set it to the node_modules version we have installed in our angular project which in our case happens to be 4.0.7. This caused the warnings to go away.

Find the details at official website
https://rxjs.dev/deprecations/subscribe-arguments
Notice the {} braces in second subscribe code below.
import { of } from 'rxjs';
// recommended
of([1,2,3]).subscribe((v) => console.info(v));
// also recommended
of([1,2,3]).subscribe({
next: (v) => console.log(v),
error: (e) => console.error(e),
complete: () => console.info('complete')
})

You can get this error if you have an object typed as Observable<T> | Observable<T2> - as opposed to Observable<T|T2>.
For example:
const obs = (new Date().getTime() % 2 == 0) ? of(123) : of('ABC');
The compiler does not make obs of type Observable<number | string>.
It may surprise you that the following will give you the error Use an observer instead of a complete callback and Expected 2-3 arguments, but got 1.
obs.subscribe(value => {
});
It's because it can be one of two different types and the compiler isn't smart enough to reconcile them.
You need to change your code to return Observable<number | string> instead of Observable<number> | Observable<string>. The subtleties of this will vary depending upon what you're doing.

I migrated my Angular project from TSLint to ESLint and it is now not showing the warning anymore!
I followed these steps. (End of each step I also recommend to commit the changes)
Add eslint:
ng add #angular-eslint/schematics
Convert tslint to eslint:
ng g #angular-eslint/schematics:convert-tslint-to-eslint
Remove tslint and codelyzer: npm uninstall -S tslint codelyzer
If you like to auto fix many of the Lint issues
ng lint --fix (It will also list the not fixed issues)
In VSCode uninstall the TSLint plugin, install ESLint plugin and Reload the VSCode.
Make sure it updated the package and package-lock files. Also the node_modules in your project.
If you have the tsconfig.json files under sub directory - you need to add/update the projects-root-directory/.vscode/settings.json with the sub directory where the tsconfig files are!
{
"eslint.workingDirectories": [
"sub-directory-where-tsconfig-files-are"
]
}
Information at VS Code official Page: Migrate from TSLint to ESLint (Thanks for pointing this out in the comment!)
Angular migrate from TSLint to ESLint Reference

I was getting the warning because I was passing this to subscribe:
myObs.subscribe(() => someFunction());
Since it returns a single value, it was incompatible with subscribe's function signature.
Switching to this made the warning go away (returns null/void);
myObs.subscribe(() => {
someFunction();
});

You should replace tslint with eslint.
As TSLint is being deprecated it does not support the #deprecated syntax of RXJS. ESLint is the correct linter to use, to do subscribe linting correctly.

The new Way of using RxJS is quit simple:
previous versions:
this.activatedRoute.queryParams.subscribe(queryParams => {
console.log("queryParams, queryParams)
}, error => {
})
New Version:
this.activatedRoute.queryParams.subscribe(
{
next: (queryParams) => {
console.log('queryParams', queryParams);
},
error: (err: any) => { },
complete: () => { }
}
);

Subscribe isn't deprecated.
So you should use:
import { of } from 'rxjs';
.subscribe({
next: (n) => console.log(n),
error: (e) => console.error(e),
complete: () => console.info('complete')
})

Related

VSCode auto import - Not working for Rxjs operators

I have a project where VS Code won't suggest imports when using rxjs operators.
myObservable.pipe(
take(1),
filter(result => result),
switchMap((result) => myOtherObserbable),
finalize(() => this.isLoading = false)
)
In this scenario, take, filter, switchMap and finalize won't provide any suggestion in the contextual menu:
I have to manually write:
import { take, filter, switchMap, finalize } from "rxjs/operators";
And then it works.
What could cause that and where should I look for?
Found out the issue in tsconfig file:
"paths": {
"#app/*": ["app/*"],
"#env/*": ["environments/*"],
"#angular/*": ["../node_modules/#angular/*"],
"rxjs/*": ["../node_modules/rxjs/*"], // => Commenting this makes the imports work
"#custom/library": ["../../../path/to/custom/library/src"]
}
I'm using a custom library and had to add paths for the project to know where to look, but apparently it brokes the auto import

How do I add a new JS function via mixin to the Magento checkout payment page's shipping information section?

I am trying to add a mixin in Magento 2 for the checkout/payment page shipping info section.
There is an existing section in vendor/magento/module-checkout/view/frontend/web/template/shipping-information/address-renderer/default.html as follows:
<each args="data: address().customAttributes, as: 'element'">
<text args="$parent.getCustomAttributeLabel(element)"/>
<br/>
</each>
I want to create a myNewFunction() and call it from here. So, I have temporarily added if="$parent.myNewFunction(element)" to it, like this:
<each args="data: address().customAttributes, as: 'element'">
<text if="$parent.myNewFunction(element)" args="$parent.getCustomAttributeLabel(element)"/>
<br/>
</each>
That pre-existing function getCustomAttributeLabel is defined in vendor/magento/module-checkout/view/frontend/web/js/view/shipping-information/address-renderer/default.js.
This is where I need to add my myNewFunction() at. I don't want to override that entire file and duplicate it into my theme, so I am trying to add the function to it via mixin.
To do this, I have stubbed out a module: app/code/MyCompany.
In this module, I have created:
app/code/MyCompany/Checkout/view/frontend/requirejs-config.js
with this code:
var config = {
config: {
mixins: {
'Magento_Checkout/js/view/shipping-information/address-renderer/default': {
'MyCompany_Checkout/js/view/shipping-information/address-renderer/default-mixin': true
}
}
}
};
Then I created the mixin itself in:
app/code/MyCompany/Checkout/view/frontend/web/js/view/shipping-information/address-renderer/default-mixin.js
with this code:
define([
'uiComponent',
'underscore',
'Magento_Customer/js/customer-data'
], function (Component, _, customerData) {
'use strict';
return function (target) {
return target.extend({
myNewFunction: function (element) {
console.log(element);
return false;
}
});
}
});
I currently have deploy mode set to "development" in Magento. Nonetheless, I have tried removing all the var/* files, generating static content again, and clearing the cache, for good measure.
No matter what, upon loading the checkout/payment page, I keep getting this JS error in the console:
$parent.myNewFunction is not a function
What am I doing wrong here?
I suspected the module needs to have a register.php? Or the module is not loading? Yet, I have seen plenty of other examples such as this guide, this Magento mixin stackoverflow question, and this example on how to add shipping.js functionality via mixin, none of which mention doing anything more with the module other than declaring the requirejs-config.js and the mixin JS file itself.
Just found a way to override that function using 'mixins'.
On requirejs-config.js file I had to add:
config: {
mixins: {
'Magento_Checkout/js/view/shipping': {
'Mynamespace_Mymodule/js/view/shipping': true
}
}
}

Flutter : A member named 'read' is defined in extensions 'ReadContext' and 'BuildContextX' and neither is more spesific

I have a button in my application that return :
onPressed: () {
return context
.read(FavoriteIds.provider.notifier)
.toggle(doa.id.toString());
},
In this case, i used a riverpod provider. But when i want to import a flutter_bloc package, the read keyword will be error with this message
A member named 'read' is defined in extensions 'ReadContext' and 'BuildContextX' and neither is more specific. Try using an extension override to specify the extension you want to to be chosen.
Please help me solve this problem. thank you :)
Here the problem is read() is defined in both ReadContext & BuildContextX extensions. So the compiler is not getting which extension to use.
To solve the error, use : ReadContext(context).read if you wanna access bloc or BuildContextX(context).read() as per your need.
This means you are importing 2 extensions that both supply the same method read. Consider this example:
extension Ext1 on String {
void foo() => print("from extension 1");
}
extension Ext2 on String {
void foo() => print("from extension 2");
}
void main() {
String s = "hello";
s.foo();
}
What should this code print? There isn't an obvious answer, and to avoid accidental programming errors, Dart prohibits this.
You could try "go-to definition" (ctrl/cmd click in most IDEs) on the read method to navigate to one of the files that it is defined in, and then delete the corresponding import statement.
However, it might be quicker to just delete all the import statements in that file and add them back with autocomplete

How to use Aurelia third party plugin with without typescript definition file?

I am new to Aurelia and Typescript. I am trying to use a the aurelia-dialog plugin inside of my project. I have follow all the necessary steps and am getting an error "cannot find module "aurelia-dialog". The offending line is
import {DialogService, DialogController} from "aurelia-dialog";
I am pretty sure all of the config is set up correctly because this is my only error. I have
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin('aurelia-dialog');
Do I need to create a typescript definition file for this to work, if so how? Or am I missing something and this should work as-is?
Looks like the aurelia-dialog build hasn't been configured to produce TypeScript definition files yet. This will probably be added soon. In the meantime you could add an aurelia-dialog.d.ts file to your project with the following:
declare module 'aurelia-dialog' {
export class DialogService {
open(settings: any): Promise;
}
export class DialogController {
constructor(renderer, settings, resolve, reject);
ok(result: any): Promise<DialogResult>;
cancel(result: any): Promise<DialogResult>;
error(message): Promise<DialogResult>;
close(ok: boolean, result: any): Promise<DialogResult>;
settings: {lock: boolean, centerHorizontalOnly: boolean };
}
export class DialogResult {
wasCancelled: boolean;
output: any;
constructor(cancelled: boolean, result: any);
}
}

broccoli-caching-writer fails with "Cannot read property 'images/.DS_Store' of undefined"

I am fairly new to broccoli and have been trying to write a simple plugin to use with ember.js. I used broccoli-caching-writer in my index.js as described on the github page for broccoli-caching-writer:
var CachingWriter = require('broccoli-caching-writer');
module.exports = CachingWriter.extend({
init: function(inputTrees, options)
{
console.log('Initializing plugin with tree');
console.log(inputTrees);
console.log(options);
this.inputTrees = inputTrees;
},
updateCache: function(srcPaths, destDir) {
console.log('updateCache called with srcPaths and destDir');
console.log(srcPaths);
console.log(destDir);
}
});
I then imported the plugin into my ember app (that uses ember CLI) and configured the following in my .brocfile
var plugin = require('broccoli-my-plugin');
var merge = require('broccoli-merge-trees');
pluginTree = new svgSpriter(['images'], {some: 'options'});
....
....
module.exports = merge([app.toTree(),pluginTree]);
Running the above with ember build command gives the following output (paths edited for privacy reasons):
Build failed.
Cannot read property 'images/.DS_Store' of undefined
TypeError: Cannot read property 'images/.DS_Store' of undefined
at CoreObject.proto.shouldBeIgnored (/node_modules/broccoli-svg-sprite/node_modules/broccoli-caching-writer/index.js:135:33)
at CoreObject.proto.keyForTree (/node_modules/broccoli-svg-sprite/node_modules/broccoli-caching-writer/index.js:277:14)
at CoreObject.<anonymous> (/node_modules/broccoli-caching-writer/index.js:267:21)
at Array.map (native)
at CoreObject.proto.keyForTree (/node_modules/broccoli-caching-writer/index.js:266:24)
at /node_modules/broccoli-caching-writer/index.js:87:20
at lib$rsvp$$internal$$tryCatch (/node_modules/broccoli-svg-sprite/node_modules/broccoli-caching-writer/node_modules/rsvp/dist/rsvp.js:489:16)
at lib$rsvp$$internal$$invokeCallback (/node_modules/broccoli-svg-sprite/node_modules/broccoli-caching-writer/node_modules/rsvp/dist/rsvp.js:501:17)
at lib$rsvp$$internal$$publish (/node_modules/broccoli-svg-sprite/node_modules/broccoli-caching-writer/node_modules/rsvp/dist/rsvp.js:472:11)
at lib$rsvp$asap$$flush (/node_modules/broccoli-caching-writer/node_modules/rsvp/dist/rsvp.js:1290:9)
It seems like the plugin is trying to check whether to ignore the path or not, but the options passed to caching writer does not have filterfromcache option defined, so the above should work? Not sure if I'm missing something?
Any help would be appreciated.
Okay, I think the example for overriding the init method needs a little update for newbies like me.
It turns out that the init method in the parent module wasn't being called. Adding the following to my init method fixed it:
CachingWriter.prototype.init.call(this, inputTrees, options);
Not sure if there is a better way though.