The function navigator.canShare() encountered a permissions denial while running in Typescript

Currently, I am in the process of developing an Angular8 PWA and have successfully implemented webshare to share text content. To my excitement, Chrome has now extended its support for file sharing starting from May 2019.

However, while attempting to integrate file sharing in Typescript, I encountered a challenging error:

Error: NotAllowedError - Permission denied

let navigator: any;
navigator = window.navigator;
const title = "myTitle";
let data = {
  title: title,
  text: text,
  url: url,
  files: []
};
console.log(data);

if (navigator.share) {
  fetch(url)
    .then(res => res.blob()) 
    .then(file => {
      const fileName = data.text + ".mp3";
      const options = { type: "audio/mp3" };
      const newFile = new File([file], fileName, options);
      data.files.push(newFile);
      console.log(data);
//lastModified: 1564912016680
//lastModifiedDate: Sun Aug 04 2019 11:46:56 GMT+0200 (Central European //Summer Time) {}
//name: "myName.mp3"
//size: 40643
//type: "audio/mpeg"
//webkitRelativePath: ""
      if (navigator.canShare(data)) {
        navigator
          .share(data)
          .then(() => {})
          .catch(err => {
            console.error("Unsuccessful share " + err.message); //Here is where I encounter the Permissions denied error
          });
      }
    });

I'm uncertain whether the issue lies with how I retrieve the file (which seems correct) or with the canShare method call. I'm using Chrome on my mobile device. The provided fiddle functions properly on my phone, although it requires selecting a file. https://jsfiddle.net/ericwilligers/8cpuskqd/

The share functionality is connected to a button containing the link of the file to be shared.

Edit

Upon converting data.files from an array to an object, a new error message surfaces:

Error: TypeError - Failed to execute 'canShare' on 'Navigator': Iterator getter is not callable.

Edit2

To replicate the problem, I have created a codepen:

https://codepen.io/anon/pen/xvXvPZ

Answer №1

Success! It's working like a charm.


function shareContent(url, text) {
    let navigator: any;
    navigator = window.navigator;
    const title = "yourTitle";
    let data = { files: [], text: text, url: url, title: title };
    const options = { type: "audio/mp3" };

    this.http
      .get(url, {
        responseType: "arraybuffer"
      })
      .subscribe(response => {
        console.log(response);

        let blob = new File([response], `${text}.mp3`, options);
        data.files.push(blob);
        console.log(data);
        if (navigator.canShare(data)) {
          navigator
            .share(data)
            .then(() => {})
            .catch(err => {
              console.error("Unsuccessful share " + err);
            });
        }
      });
  }

Answer №2

To utilize the fetch method for asynchronous operations, follow the example below:

const shareNow = async () => {
  let imageResponse = await window.fetch('https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png');
  let imageBuffer = await imageResponse.arrayBuffer();
  let fileArray = [new File([imageBuffer], "File Name", {
    type: "image/png",
    lastModified: Date.now()
  })];
  if(window.navigator && window.navigator.canShare && window.navigator.canShare({files: fileArray})){
    navigator.share({
      files: fileArray,
      title: 'Title',
      text: 'Text to show'
    }).then(() => {
      console.log('Thanks for sharing!');
    })
    .catch(console.error);
  }
}

Answer №3

import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
const navigator = window.navigator as any;

@Component({
  selector: 'app-image-post',
  templateUrl: './image-post.component.html',
  styleUrls: ['./image-post.component.css']
})
export class ImagePostComponent {

  constructor(private http: HttpClient) {}

  // Function to share image as a post
  shareNow = async () => {
    console.log("Inside shareNow method....");
    if ('canShare' in navigator) {
      console.log("Inside if condition....");
      let img = 'assets/img/image-post-1.jpg';
      const share = async function () {
        try {
          const response = await fetch(img);
          const blob = await response.blob();
          const file = new File([blob], 'rick.jpg', { type: blob.type });
          await navigator.share({
            url: img,
            title: 'Image',
            text: 'Image',
            files: [file],
          });
          console.log("Shared successfully....");
        } catch (err) {
          console.log(err.name, err.message);
        }
      };
      share();
    }
  };
<html>
<head>
 <meta name="description" content="Web Share API demo">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<title>
    Web Share API
</title>

<body>
    <div>
        <div>
            <img src="assets/img/image-post-1.jpg" alt="" style="height: 26rem; width: 26rem;">
        </div>
        <div>
            <button (click)="shareNow()" id="shareFilesButton" style="background-color: blueviolet; color: white;">Share File</button>
        </div>
    </div>
</body>

</html>

Integrate this code to enable image sharing option. Note that navigation.share works only with HTTPS, not with HTTP servers. This is an Angular example for sharing images. The image is stored in the assets/img folder; ensure you use the correct image URL for sharing.

}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible for a Firestore query using .where() to conduct a search with no results?

Currently, I am in the process of creating a platform where users can upload past exams. Each document contains various fields such as teacher, year, and class, all stored in cloud Firestore. To filter the data by teacher, I am using the .where("Teacher" ...

What is the best way to ensure that each service call to my controller is completed before proceeding to the next one within a loop in Angular?

Calling an Angular service can be done like this: this.webService.add(id) .subscribe(result => { // perform required actions }, error => { // handle errors }); // Service Definition add(id: number): Observable < any > { retu ...

Efficient Typescript ambient modules using shorthand notation

Exploring the code snippet from the official module guide, we see: import x, {y} from "hot-new-module"; x(y); This syntax raises a question: why is 'x' not within curly brackets? What does this coding structure signify? ...

Invoke a general function with corresponding generic parameters

I am currently working on a function that takes another function and its arguments as parameters, then runs the function with the provided arguments and returns the result while maintaining the data types. If the function being provided has a fixed return ...

What is the best way to generate a type that generates a dot notation of nested class properties as string literals?

In relation to the AWS SDK, there are various clients with namespaces and properties within each one. The library exports AWS, containing clients like DynamoDB and ACM. The DynamoDB client has a property named DocumentClient, while ACM has a property call ...

Error encountered while installing node modules within an angular workspace

Currently, I am facing an issue with my workspace where the command npm install is giving me a series of errors that I cannot seem to resolve. I have tried running it as an admin, manually deleting the node_modules folder, asking for help from a senior col ...

Deactivate the react/jsx-no-bind warning about not using arrow functions in JSX props

When working with TypeScript in *.tsx files, I keep encountering the following error message: warning JSX props should not use arrow functions react/jsx-no-bind What can I do to resolve this issue? I attempted to add configurations in tslint.json js ...

Invoking a nested class while declaring types in TypeScript

This is the specific format of data that I am in need of this.structure=[ { id: 1, name: 'root1', children: [ { id: 2, name: 'child1' }, { id: 3, name: 'child2' } ] }, { ...

No matter which port I try to use, I always receive the error message "listen EADDRINUSE: address already in use :::1000"

Encountered an error: EADDRINUSE - address already in use at port 1000. The issue is within the Server setupListenHandle and listenInCluster functions in the node.js file. I am currently running this on a Mac operating system, specifically Sonoma. Despit ...

Tips for displaying backend error messages on the frontend

I am facing an issue with returning error messages from the backend to the frontend in my Angular project. The specific requirement is to display an error message when the value of msisdn is not eligible for renewal. Currently, the hardcoded error message ...

The recursive component is functional exclusively outside of its own scope

I'm facing an issue where my recursive component is not nesting itself properly. The problem arises when I try to use the Recursive component inside another Recursive component. Although the root is correctly inserted into the Recursive component fro ...

The specified type 'IterableIterator<number>' does not belong to either an array type or a string type

Encountering an error while attempting to generate a dynamic range of numbers. Error: Type 'IterableIterator<number>' is not recognized as an array or string type. Use the compiler option '--downlevelIteration' to enable iteratio ...

Mastering the art of accessing properties in typescript post implementing Object.defineProperty

I was experimenting with the TypeScript playground trying to figure out decorators and encountered some questions. class PathInfo { functionName: string; httpPath: string; httpMethod: string; constructor(functionName: string, httpPath: str ...

Allow TypeScript function parameters to accept multiple elements from an enumeration

Enumerating my options. export enum Selection { CHOICE_ONE = 'one', CHOICE_TWO = 'two', CHOICE_THREE = 'three', CHOICE_FOUR = 'four', } I am looking to design a function that accepts an array, but re ...

How can we initiate an AJAX request in React when a button is clicked?

I'm fairly new to React and I'm experimenting with making an AJAX call triggered by a specific button click. This is how I am currently using the XMLHttpRequest method: getAssessment() { const data = this.data //some request data here co ...

Angular is showing an error indicating that the property "name" is not found on an empty object

After thorough checking, I have confirmed that the property does exist with the correct key. However, it is returning an error message stating name is not a property of {}. I attempted to assign this object to an interface along with its properties but enc ...

How to retrieve the default type returned by a function using a custom TypeMap

I have a function that returns a promise with a type provided by generics. const api = <Model>(url: string) => Promise<Model> Currently, I always need to set the type of the returned data. const data = await api<{id: string, name: string ...

Selenium Grid: Unable to locate the DevToolsActivePort file (error: Chrome did not launch successfully and exited abnormally)

Recently, I decided to use Selenium Grid to automate some tests. To make the process more efficient, I set up VMs running on a LINUX Platform (one acting as a Selenium hub and others as Selenium nodes). The standalone server started without any issues in b ...

Is it feasible to implement early-return typeguards in Typescript?

There are instances where I find myself needing to perform type checks on variables within a function before proceeding further. Personally, I try to minimize nesting in my code and often utilize early-return statements to keep the main functionality of a ...

Difficulty in monitoring the present machine status through XState in a React application

I'm encountering an issue where I am trying to access the Machine state from within a function in a React component using state.value. However, the current state never changes and it always displays the initial state. Strangely, if I include an onClic ...