Categories
discuss

How can I pass props down in Angular 2+ like React?

In react I can arbitrarily pass props down like so:

function SomeComponent(props) {
  const {takeOutProp, ...restOfProps} = props;
  return <div {...restOfProps}/>;
}

How can I do the same thing in Angular?

More specifically, I want to write a custom dropdown component and pass props down to a select box.

Answer

As opposed to React components, Angular components aren’t recompiled on input changes and use @Input property decorators to enable change detection. All properties that are expected to be passed should be explicitly defined as component inputs.

There are no better options than this one for custom select component. It’s possible to read static attributes from current component element and set them on nested component element, but this won’t set up bindings.

As for React recipe for deep props in wrapped components:

const Baz = props => <p>{props.baz}</p>;
const Bar = props => <Baz {...props} />;
const Foo = props => <Bar {...props} />;

This is usually handled by Angular DI and a hierarchy of injectors. A provider can be defined on respective injector in order to make data and behaviour available to nested components.

Categories
discuss

How to create Asynchronous Call using Retrofit and Observables in Kotlin?

I want to make API calls using Retrofit2 library, returns generic type observable.

I am getting an error: android.os.NetworkOnMainThreadException, while making calls.

Answer

Looks really easy to solve, two cases to consider. :1)If you are not using RXJava or 2) if you are using it

1) If you are NOT using RXJava

You should use the method enqueue when you make the call. The error you get is because you are calling the response on the same Thread(the MainThread)

Here is an example took from the web that uses Enqueue with Kotlin that possibly you can adapt to your case

override fun loadPokemonList(pokemonListListener: PokemonListListener) {


    call = pokemonService.getPokedex();
    call.enqueue(object : Callback<PokeDex> {
        override fun onResponse(call: Call<PokeDex>?, response: Response<PokeDex>?) {

            if (response != null && response.isSuccessful) {
                pokemonListListener.onSuccess(response.body())
            } else {
                pokemonListListener.onFailure(appContext.getString(R.string.error_fetching_data))
            }


        }

        override fun onFailure(call: Call<PokeDex>?, t: Throwable?) {
            pokemonListListener.onFailure(appContext.getString(R.string.error_fetching_data))
        }
    })


 }

2) If you are using RXJava(usually version 2, be aware you will find several tutorials for the first version online)

But please consider that most of the developers today solve this asynchronous call using RXJava2 that is the second case I was mentioning at the beginning of he post. It will take you several hours to understand the basics of it but once you will do, you will have a great skill to bring with you and manage this kind of calls( even multiple ones) will be really simple. In fact RXJava allows you really easy to direct the operation in a concurrent Thread and observe the result on the Main Thread. Here a good tutorial that explains how to do that with the easy and well known pattern (see the notations)

Observable<List<TrendsResponse>>
    .subscribeOn(Schedulers.io())//Run the call on another Thread
    .observeOn(AndroidSchedulers.mainThread())//observe on the Main Thread
    .subscribe();

Differently by what people new to RXJava think: on default RXJava does not call a concurrent Thread, is up to you to do that with the subcribeOn that does all the “dirty” work and then to observe the result on the Main Thread with ObserveOn.

For principiants is easy to grasp that comparing both of them to the two famous methods of AsyncTask: doInBackground and onPostExecute

EDIT: Please look also this post if you or future users have problems.

Categories
discuss

Check javascript compatibility with Internet explorer

I have some javascript code that does not run in IE 11. Is there a quick way to check where the incompatibly is other than going through the code line by line to see what commands and statements are supported by that version of Internet Explorer?

Answer

Solved the issue by using JSHint (installed as package on Sublime Text 3) with option “esversion” set to 3 (compatibility with ECMAScript 3). This got me 90% of the way there and I did the rest manually.

Categories
discuss

onMetadataChanged MediaControllerCompat.Callback never called

I’m developing a simple Audio Player app for a radio station.
I have successfully made a MediaBrowser and registered a callback to listen for playBack– or metadata changes.

var mediaBrowser : MediaBrowserCompat by Delegates.notNull()
mediaBrowser = MediaBrowserCompat(
        activity,
        ComponentName(activity, MediaPlaybackService::class.java),
        object : MediaBrowserCompat.ConnectionCallback() {
            override fun onConnected() {
                val mediaController = MediaControllerCompat(activity, mediaBrowser.sessionToken)
                MediaControllerCompat.setMediaController(activity, mediaController)
                mediaController.registerCallback(ControllerCallback)
                mediaControllerFunc()
            }
        },
        null
)

object ControllerCallback : MediaControllerCompat.Callback() {
    override fun onMetadataChanged(metadata: MediaMetadataCompat) {
        //TODO: Never called
    }

    override fun onPlaybackStateChanged(state: PlaybackStateCompat) {
        //Called
    }
}

The playback changes are received when I call

mediaSession.setPlaybackState(
    PlaybackStateCompat.Builder()
            .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
            .setState(STATE_PLAYING, DEFAULT_PLAYBACK_POSITION, DEFAULT_PLAYBACK_SPEED)
            .build()
)

However metadata changes are not.
Even though I call

mediaSession.setMetadata(
    MediaMetadataCompat.Builder()
        .putLong(METADATA_KEY_DURATION, -1)
        .putString(METADATA_KEY_TITLE, title)
        .putString(METADATA_KEY_ARTIST, artist)
        .putBitmap(METADATA_KEY_ALBUM_ART, albumCover)
        .putString(METADATA_KEY_ALBUM_ART_URI, albumCoverUrl)
        .build()
)

What am I missing to receive metadata changes?
If it can help the complete repository is available on Github

Thanks in advance

Answer

My solution for anybody experiencing the same problem.

It turned out I was mixing compat (service layer responsible for starting the audio service and connection to metadata) and non compat (UI layer) variants of the API.

In particular the activity.
Since I am targeting Lollipop and higher I decided to use Activity instead of the AppCompatActivity.

This apparently silently breaks the MediaControllerCompat.Callback for onMetadataChanged(), but not for onPlaybackStateChanged().
Can’t seem to find why?!

In code it is as simple as changing:

class PlayableActivity : Activity() { ... }

to:

class PlayableActivity : AppCompatActivity() { ... }

Categories
discuss

Is there a way to run some tests sequentially with Jest?

Jest runs your test suite in parallel by default, but there is a flag (--runInBand) that allows you to run the whole suite sequentially (as pointed out here)

I have some tests that cannot run in parallel, but running the whole suite sequentially takes a lot longer in total, so my question is if there is way to only run some tests that way (such as setting a flag for those tests or something similar).

Answer

I too needed the same functionality. I have a large set of Jest integration test suites I want to run. However, some can’t be run in parallel due to the need of setup and teardown of a shared resource. So, here is the solution I came up with.

I updated my package.json scripts from:

{
  ...
  "scripts": {
    ...
    "test": "npm run test:unit && npm run test:integration",
    "test:integration": "jest --config=__tests__/integration/jest.config.js",
    "test:unit": "jest --config=__tests__/unit/jest.config.js"
  },
  ...
}

to

{
  ...
  "scripts": {
    ...
    "test": "npm run test:unit && npm run test:integration",
    "test:integration": "npm run test:integration:sequential && npm run test:integration:parallel",
    "test:integration:parallel": "jest --config=__tests__/integration/jest.config.js",
    "test:integration:sequential": "jest --config=__tests__/integration/jest.config.js --runInBand",
    "test:unit": "jest --config=__tests__/unit/jest.config.js"
  },
  ...
}

Then I updated __tests__/integration/jest.config.js from

module.exports = {
  // Note: rootDir is relative to the directory containing this file.
  rootDir: './src',
  setupFiles: [
    '../setup.js',
  ],
  testPathIgnorePatterns: [
    ...
  ],
};

to

const Path = require('path');

const { defaults } = require('jest-config');
const klawSync = require('klaw-sync')
const mm = require('micromatch');

// Note: rootDir is relative to the directory containing this file.
const rootDir = './src';
const { testMatch } = defaults;

// TODO: Add the paths to the test suites that need to be run
// sequentially to this array.
const sequentialTestPathMatchPatterns = [
  '<rootDir>/TestSuite1ToRunSequentially.spec.js',
  '<rootDir>/TestSuite2ToRunSequentially.spec.js',
  ...
];

const parallelTestPathIgnorePatterns = [
  ...
];

let testPathIgnorePatterns = [
  ...parallelTestPathIgnorePatterns,
  ...sequentialTestPathMatchPatterns,
];

const sequential = process.argv.includes('--runInBand');
if (sequential) {
  const absRootDir = Path.resolve(__dirname, rootDir);
  let filenames = klawSync(absRootDir, { nodir: true })
    .map(file => file.path)
    .map(file => file.replace(absRootDir, ''))
    .map(file => file.replace(/\/g, '/'))
    .map(file => '<rootDir>' + file);
  filenames = mm(filenames, testMatch);
  testPathIgnorePatterns = mm.not(filenames, sequentialTestPathMatchPatterns);
}

module.exports = {
  rootDir,
  setupFiles: [
    '../setup.js',
  ],
  testMatch,
  testPathIgnorePatterns,
};

The updated jest.config.js depends on jest-config, klaw-sync, and micromatch.

npm install --save-dev jest-config klaw-sync micromatch

Now, you can run npm run test:integration:sequential if you only want to run the tests that need to be run sequentially.

Or run npm run test:integration:parallel for the parallel tests.

Or run npm run test:integration to first run the sequential tests. Then when that is finished, the parallel tests will run.

Or run npm run test to run both the unit and integration tests.

Note: The directory structure I am using with my unit and integration tests is as follows:

__tests__
  integration
    src
      *.spec.js
      *.test.js
    jest.config.js
  unit
    src
      *.spec.js
      *.test.js
    jest.config.js
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..