Angular.js: suporta ligação de entrada [type = arquivo]

Criado em 18 set. 2012  ·  145Comentários  ·  Fonte: angular/angular.js

oi tentando fazer um upload de arquivo simples :) mas a entrada de type = file não parece ligar ive tentei hg-model-instant mas não obtive nada, mesmo atualizado para 1.0.2 e nada

forms moderate not core feature

Comentários muito úteis

Esta solução depende do filereader sendo implementado:

...
.directive('file', function() {
    return {
        restrict: 'E',
        template: '<input type="file" />',
        replace: true,
        require: 'ngModel',
        link: function(scope, element, attr, ctrl) {
            var listener = function() {
                scope.$apply(function() {
                    attr.multiple ? ctrl.$setViewValue(element[0].files) : ctrl.$setViewValue(element[0].files[0]);
                });
            }
            element.bind('change', listener);
        }
    }
});

<file name="image" ng-model="inputFile" accept="image/png,image/jpg,image/jpeg" />

Em seguida, você terá que fazer algumas coisas xhr sozinho, mas acredito que isso está fora da vinculação gui e mais lógica de processamento.

e se você não tem imaginação:

var file = $scope.inputFile;
$http.put('http://localhost:5984/demo/d06917e8d1fae1ae162ea7773c003f0b/' + file.name + '?rev=4-c10029f35a5c5ed9bd8cc31bf8589d3c', file, { headers: { 'Content-Type' : file.type } });

Isso funciona por causa do xhr2 (http://www.html5rocks.com/en/tutorials/file/xhr2) e desculpe o URL de upload de exemplo longo, é um endpoint de documento couchdb (anexo).

Todos 145 comentários

Não há ligação padrão fornecida pelo angular para input type = file.

Mas então, a entrada do arquivo é real apenas para javascript, o único benefício que tal ligação pode ajudar é limpar a entrada do arquivo. (O Angular também não fornece suporte de estrutura para upload de arquivo ajax agora, eu acredito)

@coli : essa não é toda a verdade.

Faria sentido ser capaz de capturar o evento onchange na entrada [arquivo].

Em https://github.com/lgersman/jquery.orangevolt-ampere , temos exatamente esse cenário: uploads de arquivos via XMLHTTPRequest V2.
Portanto, implementamos nossa própria diretiva para capturar eventos de mudança de entrada [arquivo] para fazer uploads de arquivos sem recarregar a página.

Eu adoraria ver esse recurso no angularjs!

Houve algum progresso com a vinculação a uma entrada do arquivo do tipo? Tenho procurado uma solução e não consigo encontrar uma que funcione ...

minha solução foi apenas Ajax em vez de request ou http.post

Enviado do meu iPad

Em 1º de março de 2013, às 19h16, "jgoldber" < [email protected] [email protected] > escreveu:

Houve algum progresso com a vinculação a uma entrada do arquivo do tipo? Tenho procurado uma solução e não consigo encontrar uma.

-
Responda a este e-mail diretamente ou visualize-o em Gi tHubhttps: //github.com/angular/angular.js/issues/1375#issuecomment -14321221.

Melhor solução que encontrei: http://jsfiddle.net/marcenuc/ADukg/49/. Por favor, compartilhe se você encontrar uma solução melhor.

Sim, isso realmente precisa ser examinado; ser capaz de selecionar e fazer upload de um arquivo é crucial para a maioria dos aplicativos da web, portanto, o suporte a essa entrada é um recurso ausente bastante óbvio.

Ressalto. Isso precisa ser adicionado a um marco.

Outro grito em apoio a isso.

O arquivo do modelo ng pode definir o valor de um arquivo da API de arquivo HTML5, existem polyfills Flash e Silverlight para IE8 / IE9

Sim, defina o valor para o arquivo ou para o elemento de entrada (contendo referência ao arquivo)

Esta solução depende do filereader sendo implementado:

...
.directive('file', function() {
    return {
        restrict: 'E',
        template: '<input type="file" />',
        replace: true,
        require: 'ngModel',
        link: function(scope, element, attr, ctrl) {
            var listener = function() {
                scope.$apply(function() {
                    attr.multiple ? ctrl.$setViewValue(element[0].files) : ctrl.$setViewValue(element[0].files[0]);
                });
            }
            element.bind('change', listener);
        }
    }
});

<file name="image" ng-model="inputFile" accept="image/png,image/jpg,image/jpeg" />

Em seguida, você terá que fazer algumas coisas xhr sozinho, mas acredito que isso está fora da vinculação gui e mais lógica de processamento.

e se você não tem imaginação:

var file = $scope.inputFile;
$http.put('http://localhost:5984/demo/d06917e8d1fae1ae162ea7773c003f0b/' + file.name + '?rev=4-c10029f35a5c5ed9bd8cc31bf8589d3c', file, { headers: { 'Content-Type' : file.type } });

Isso funciona por causa do xhr2 (http://www.html5rocks.com/en/tutorials/file/xhr2) e desculpe o URL de upload de exemplo longo, é um endpoint de documento couchdb (anexo).

É possível fazer isso funcionar no IE8 / 9 combinando este FileReader Polyfill baseado em flash https://github.com/Jahdrien/FileReader e este polyfill js FormData puro que depende de FileReader https://github.com/francois2metz/ html5-formdata. _update_ Moxie é um polyfill melhor

Minha solução foi bastante superficial, pelo menos tão incompleta quanto o jsfiddle acima, onde o protótipo do controlador é manipulado com ...

No controlador:

    $scope.updateImage = '(' + function () {
      alert('moo');
    }.toString() + ')();';

Stringify meu retorno de chamada onchange desejado e envolva-o em um encerramento.

   <input type="file" name="image" onchange="{{updateImage}}" ng-model="image">

Insira-o no DOM usando Angular

Não é exatamente bonito, mas funciona no Webkit. Eu não fiz nenhum teste cruzado do navegador.

Estou no 1.0.5 e ainda está quebrado. Usamos o exemplo de Jgoldber e o ajustamos um pouco:
http://jsfiddle.net/ADukg/2589/

Este exemplo funcionará apenas para um controlador, portanto, se você tiver vários controladores, cada um com entradas de arquivo, você precisará fazer algumas alterações.

Ainda não testei no IE, mas meu palpite (conhecendo o IE) é que não funcionará.

Supondo que você deseja apenas chamar uma função em seu escopo que leva o elemento de entrada como um argumento, isso é bastante simples de implementar em uma diretiva:

http://jsfiddle.net/neilsarkar/vQzKJ/

(modificado do jsfiddle acima, obrigado @programmist)

'use strict';

function filesModelDirective(){
  return {
    controller: function($parse, $element, $attrs, $scope){
      var exp = $parse($attrs.filesModel);

      $element.on('change', function(){
        exp.assign($scope, this.files);
        $scope.$apply();
      });
    }
  };
}

configuração:

angular.module(...).directive('filesModel', filesModelDirective)

uso:

<input type="file" files-model="someObject.files" multiple>

Por favor, corrija isso logo.

Ainda tendo problemas .. em algumas versões funciona, mas de qualquer forma não é suportado

Desde 1.5.0 $ digest deve ser chamado se você estiver usando uma solução alternativa onchange:

<input type="file" onchange="angular.element(this).scope().myController.uploadFile(this.files[0]); angular.element(this).scope().$digest();">

+1 para melhor suporte na mudança de ng e a entrada / arquivo. Caso de uso: como um uploader de uma imagem, gostaria de poder editar essa imagem (redimensionar e cortar) antes de enviar para uma exibição ideal. Implementação: navegue até a imagem (usando entrada / arquivo) e no evento onchange mova o arquivo para a tela e edite com fabricjs. Não consigo pensar em uma implementação de mudança não ativa.

cztomsik - Estou no 1.0.7 e não consigo fazer sua solução funcionar - a função de escopo (esta) resolve bem, mas o controlador não pode ser encontrado, a função uploadFile está listada como um membro do escopo (este).

Brincando, fiz uma pequena modificação na técnica, que parece estar funcionando para mim (ainda não sei por que tinha:

<input type = "file" name = "file" ng-model = "file" onchange = "invokeUploadFile (this)" />

var invokeUploadFile = function (that) {
angular.element (that) .scope (). uploadFile (that)
angular.element (that) .scope (). $ digest ();
}

Você poderia fornecer jsfiddle / plunker?
Valeu


    1. 2013 v 18:17, tb01923 [email protected] :

+1 para melhor suporte na mudança de ng e a entrada / arquivo. Caso de uso: como um uploader de uma imagem, gostaria de poder editar essa imagem (redimensionar e cortar) antes de enviar para uma exibição ideal. Implementação: navegue até a imagem (usando entrada / arquivo) e no evento onchange mova o arquivo para a tela e edite com fabricjs. Não consigo pensar em uma implementação de mudança não ativa.

cztomsik - Estou no 1.0.7 e não consigo fazer sua solução funcionar - a função escopo (esta) resolve bem, mas o controlador não pode ser encontrado, a função uploadFile está listada como um membro do objeto escopo (este), mas quando eu remova o controlador que recebo

ReferenceError não capturado: uploadFile não está definido blah.js: 15
$ scope.uploadFile blah.js: 15
invokeScope blah.js: 4
em mudança

-
Responda a este e-mail diretamente ou visualize-o no GitHub.

+1. Necessário para iniciar o upload de um arquivo HTML5 quando um usuário seleciona um arquivo. É fácil de contornar, mas espero que funcione.

+1. por favor, implemente, não implementando não é totalmente intuitivo.

+1

+1

Qual é, gente .. já faz mais de um ano e o angular 1.2.0 ainda não tem vínculos de arquivo de entrada ... Não entendo porque o recurso não está sendo adicionado? Houve algumas boas soluções para a implementação. Eu gostaria de uma resposta angular de um membro da equipe sobre o problema, por favor.

Apenas para citar uma das melhores soluções (eu sei que é uma ligação de dados unilateral, mas ainda melhor do que nada, a validação e atualização do modelo funcionam mesmo no IE7):

Definição

  /**
   * <strong i="8">@ngdoc</strong> inputType
   * <strong i="9">@name</strong> angular.module.ng.$compileProvider.directive.input.file
   *
   * <strong i="10">@description</strong>
   * HTML file input field.
   *
   * <strong i="11">@param</strong> {string} ngModel Assignable angular expression to data-bind to.
   * <strong i="12">@param</strong> {string} multiple Allows multiple files selection.
   * <strong i="13">@param</strong> {string=} name Property name of the form under which the 
                                control is published.
   *
   * <strong i="14">@example</strong>
      <doc:example>
        <doc:source>
         <script>
           function Ctrl($scope) {
           }
         </script>
         <form name="myForm" ng-controller="Ctrl">
           file: <input type="file" ng-model="file"> single file selection.<br/>
           files: <input type="file" ng-model="files" multiple> multi-file selection.<br/>
           <tt>file.name = {{file.name}}</tt><br/>
           <tt>files.length = {{files.length}}</tt><br/>
          </form>
        </doc:source>
        <doc:scenario>
          it('should change state', function() {
            expect(binding('file.name')).toBeUndefined();

            input('file').select('a file name');
            expect(binding('file.name')).toEqual('a file name');
          });
        </doc:scenario>
      </doc:example>
   */
  'file': fileInputType,

Função

function fileInputType(scope, element, attr, ctrl) {
  element.bind('change', function() {
    scope.$apply(function() {
      var files = element[0].files,
          isValid = true;

      if (msie < 10) {
        files = [element[0].value];
      }

      if (attr.accept) {
        var i, j, acceptType, fileType,
            types = map(attr.accept.split(','), function(t) { return trim(t).split('/'); });
        for (i = 0; i < files.length && isValid; ++i) {
          fileType = files[i].type.split('/');
          isValid = false;
          for (j = 0; j < types.length && !isValid; ++j) {
            acceptType = types[j];
            isValid = acceptType[0] === fileType[0] && (acceptType[1] === '*' || acceptType[1] === fileType[1]);
          }
        }
      }
      ctrl.$setValidity('file', isValid);

      var viewValue;
      if (isValid) viewValue = attr.multiple ? files : files[0];
      ctrl.$setViewValue(viewValue);
    });
  });
}

+1

+1

@ntrp Por que você não faz RP para essa mudança?

Essa mudança precisa ser um pouco elaborada e testada, não tenho tempo no momento para fazer isso.

+1

+1

-1: trollface:

Criança +1

+1

+1

+1

+1

+1

input [type = file] não é realmente uma ligação bidirecional, a menos que usemos explicitamente a API File, que não está disponível em todos os navegadores de destino. Adicionar isso ao ng-model não faz muito sentido, mas existem vários plug-ins que suportam algumas variações dessa funcionalidade. Não podemos simplesmente delegar isso aos plug-ins por um tempo?

http://caniuse.com/fileapi

@caitp Certo, mas faz sentido ser capaz de vincular ao evento change, via ng-change, que não funciona.

Outra coisa que não funciona é a validação do formulário. Acho que o suporte a arquivos deve ser implementado para novos navegadores com fallback de ligação de dados unidirecional para os antigos. Se esta solução não for viável então, na minha opinião, deve ser claramente indicado no wiki porque a funcionalidade não está implementada e como resolver os problemas que esta falta de suporte causa. Lembro-me de perder muito tempo antes de resolver minhas necessidades de arquivo de entrada quando os usei pela primeira vez.

A questão é que os nomes de arquivos não estão vinculados a um modelo e não faria sentido vinculá-los a um modelo. Cada propriedade da interface File é somente leitura, e a interface FileList é apenas uma coleção de Files. Não há capacidade para vinculação bidirecional, portanto, não há razão real para usar o modelo ng para elas em primeiro lugar. É bastante simples vincular ao evento change vez disso, e você pode facilmente escrever uma diretiva para adicionar essa funcionalidade para que possa usá-la declarativamente se precisar.

Mas como faz sentido tornar isso parte do modelo ng quando ele não tem a capacidade de seguir o comportamento do modelo ng?

Não há razão para que não seja possível criar uma interface personalizada para arquivos, e o angular pode fazer isso em algum ponto, mas realmente não faz sentido com o ng-model na minha opinião. Não sei o que os outros desenvolvedores pensam sobre isso, eles podem concordar ou não. Mas, da minha perspectiva, uma diretiva separada faria mais sentido, porque input [type = file] simplesmente não se encaixa no ng-model

  • Nada sobre o valor de uma entrada de arquivo é gravável a partir de um contexto de script
  • Não temos uma maneira real de realizar a validação aqui sem a API de arquivo (que não é suportada em vários navegadores de destino), o navegador faz isso para nós, essencialmente. --- com exceção da validação ngRequired

A única coisa que realmente poderíamos fazer para input [type = file] é $ setViewValue quando o valor muda (o que realmente não faz sentido), e de alguma forma mudar o ngModel para ignorar mudanças no valor do modelo causadas por uma mudança de script (ou basicamente apenas desative o $ watch completamente). Quanto à validação, tudo o que podemos realmente suportar é ng-required, quero dizer, o que mais podemos fazer lá?

Eu gostaria de poder oferecer suporte a uma entrada de arquivo com o ngModel também, mas não vejo como isso funcionaria, simplesmente não se encaixa na interface do ngModel.

Eu concordo com essa afirmação, mas, como disse antes, precisamos dar mais ênfase a isso no wiki ou, em geral, na documentação, para que os desenvolvedores saibam o que precisam fazer para obter a funcionalidade de que precisam.

@ntrp well docs patches são mais do que bem-vindos, e ficarei feliz em revisar se você enviar um :)

Adicionar uma diretiva específica no angular pode ser uma solução?

Eu concordo com a afirmação anterior, mas parece pelo menos um pouco estranho que um
estrutura como angular não tem uma maneira clara e limpa de alcançar
isto...
Esta foi provavelmente a coisa mais desorientadora que tive de enfrentar ao tentar
enviar um arquivo...

Ah ok @caitp , eu li há algum tempo que a solicitação de pull do wiki não estava realmente sendo avaliada ativamente, então não me incomodei em contribuir. Se eu tiver algum tempo livre logo, terei prazer em contribuir :) obrigado.

Não percebi que a diretiva ngChange exigia que o ngModel também estivesse presente, e acho que é por isso que há tanta discussão sobre ngModel aqui (e é por isso que recebo esse erro ). Concordo que a ligação bidirecional em uma entrada [type = file] não faz sentido.

Mas qual é a razão exata pela qual o ngModel é exigido pelo ngChange? Em minha opinião, faz todo o sentido ser capaz de vincular ao evento de alteração de um campo de entrada [type = arquivo], digamos, se você quiser enviar automaticamente o formulário assim que um arquivo for escolhido. Nesse caso, eu realmente não me importo qual é o valor do campo. Eu só me importo se isso mudou. A melhor maneira que descobri de lidar com isso é através da solução alternativa mencionada por @cztomsik :

onchange="angular.element(this).scope().fileChangedHandler()"

E isso realmente não parece ser a melhor solução.

ng-change , apesar de ser nomeado de forma semelhante às outras diretivas de manipulador de eventos, não é realmente um manipulador para o evento change . Ele apenas adiciona um $viewChangeListener ao ngModelController, que é acionado sempre que $setViewValue é chamado.

Eu concordo que é um nome infeliz

Este é um dupe de # 1236, que foi fechado com este comentário: https://github.com/angular/angular.js/issues/1236#issuecomment -29115377

a menos que vejamos uma proposta sobre como implementar isso para que seja leve, mas funcional e não exija forçar um estilo ux para usuários de framewok, vamos considerá-la. Mas agora, pensamos que os problemas de upload de arquivos são complexos o suficiente para serem resolvidos como um módulo separado, provavelmente fora do núcleo.

+1

@IgorMinar dá uma olhada aqui, um exemplo meio sujo, mas muito interessante de implementação: https://github.com/danialfarid/angular-file-upload. @danialfarid está fazendo um grande progresso com isso.

Veja como isso é um problema para todos, várias questões abertas com vários comentários. Você deve fornecer um módulo ngUpload para nós: smile : https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills#file -api a http://docs.angularjs.org/guide / ie.

Como você está pensando em resolver?

+1

+1

+1

+1

+1

+1

+1

+1

Uau, é um pouco constrangedor nesta fase.

+1

Não é realmente possível ter ligações bidirecionais para entradas de arquivo, certamente quando os navegadores de destino nem todos suportam a API de arquivo (http://caniuse.com/fileapi) --- Mas mesmo quando podem, input[type=file] realmente não se encaixa nisso de qualquer maneira. A ligação bidirecional é realmente impossível

Sinto muito, mas este é mais um problema / recurso de segurança da plataforma da web do que qualquer outra coisa. Se fosse factível, seria feito

@caitp Eu

Algo tão simples como um invólucro para isso, por exemplo, seria um começo.

Dada a direção que o Angular 2.0 está tomando (transpilando apenas angular, idiomas não ECMA), não acho que as limitações da "plataforma da web" devam ser uma preocupação.

@todos os outros: O que o Ember faz neste caso?

Editar: remover "necessário" da instrução de transpilação.

_Só um rápido esclarecimento._ A construção de aplicativos Angular 2.0 não requer uma linguagem transpilada ou idiomas não ECMA. Você pode usar o código ES5 simples perfeitamente. Se você deseja construir o código-fonte do Angular 2.0, você precisa usar o traceur para compilar. Naturalmente, você pode usar o traceur para construir seus próprios aplicativos e tirar proveito dos mesmos recursos que usamos no Angular, mas isso é totalmente opcional. Desculpe se houve alguma confusão sobre esse ponto em nossos anúncios.

@EisenbergEffect My bad. Eu sabia disso e deveria ter revisado melhor. Sem café!

Frameworks não podem realmente contornar as limitações da plataforma web. Por exemplo, não podemos forçar o navegador a nos permitir escrever em atributos IDL somente leitura (o que realmente quebra a ligação bidirecional para arquivos) e não podemos forçar o navegador a expor o sistema de arquivos para nós, o que realmente nos impede de fazer qualquer coisa interessante com isso

@caitp Já faz algum tempo que acompanho esse assunto. Acho que parece haver desejo da comunidade suficiente para que o Angular ofereça suporte a uma entrada de seleção de arquivo simples. Atualmente (a menos que eu esteja enganado), construir um aplicativo trivial que aceita um arquivo e o carrega via XHR usando Angular não tem um padrão recomendado a seguir? Isso soa como um recurso que merece pelo menos alguma atenção além de "desculpe, não posso fazer isso porque a vinculação bidirecional não faz sentido aqui."

Talvez possamos reorientar essa conversa para: "Como o angular poderia apoiar isso?" em vez de "Não se encaixa em nossos padrões atuais".

Vincular a entrada de arquivo é definitivamente possível, eu fiz isso em um projeto anterior para AngularJS na verdade.

O fato de que você não pode fazer uma ligação bidirecional com entradas de arquivo é um recurso de segurança, e isso faz sentido. Os autores nunca poderão definir o caminho do arquivo via script, mas por que não vinculá-lo apenas de uma forma?

Claro que quebra o paradigma, mas quem realmente se importa se isso significa que você obtém uma mudança de ng e capacidade de acessar arquivos via API de arquivo sem hacks? O jQuery pode se vincular a um evento de mudança nas entradas de arquivo. O caminho Angular é tão sagrado que não podemos simplesmente vinculá-lo a um controlador? É uma limitação técnica da arquitetura ou apenas uma barreira ideológica?

Concordo, eu estava menos preocupado com a ligação bidirecional. Eu simplesmente queria postar o arquivo com o resto do meu documento sem perder tempo.

Em 20 de maio de 2014, às 7h53, Justin Arruda < [email protected] [email protected] > escreveu:

@c aitphttps: //github.com/caitp Venho acompanhando esse problema há algum tempo. Acho que parece haver desejo da comunidade suficiente para que o Angular ofereça suporte a uma entrada de seleção de arquivo simples. Atualmente (a menos que eu esteja enganado), construir um aplicativo trivial que aceita um arquivo e o carrega via XHR usando Angular não tem um padrão oficial a seguir? Isso não soa como um recurso que merece pelo menos alguma atenção além de "desculpe, não posso fazer isso porque a vinculação bidirecional não faz sentido aqui."

Talvez possamos reorientar essa conversa para: "Como o angular poderia apoiar isso?" em vez de "Não se encaixa em nossos padrões atuais".

-
Responda diretamente a este e-mail ou visualize-o em Gi tHubhttps: //github.com/angular/angular.js/issues/1375#issuecomment -43636326.

Então você tem um caso em que ng-model se comporta de maneira totalmente diferente para um controle de formulário específico, e então você tem pessoas preenchendo bugs como "como o controle de formulário envia o arquivo errado quando eu mudo o valor para" foobarblah.txt "ou qualquer outra coisa. API inconsistente -> ruim.

O ngModel não é totalmente ideal para essas coisas especificamente porque significa que temos um padrão específico para se encaixar e é muito difícil para os autores de aplicativos desligarem. No entanto, existem soluções para isso no angular.dart e no protótipo v2.0.0, portanto, será melhor no futuro. Mas nós realmente não podemos adicionar outro comportamento do modelo ng que ignore tudo o que o modelo ng faz atualmente, não faria sentido

aceita um arquivo e o carrega via XHR usando Angular

@guruward , não podemos oferecer suporte a isso em todos os nossos navegadores de destino para 1.x sem forçar as pessoas a usar polyfills shockwave ou similares. Existem módulos de terceiros que permitem isso e podem ser usados ​​em seu lugar. O angular-file-upload fornece as versões shockwave polyfill e html5 nativas simultaneamente e escolhe a correta. Portanto, não é uma solução ruim, altamente recomendável se você quiser fazer isso.

Mas não tenho certeza se é algo que podemos colocar no núcleo, você teria que perguntar a Igor o que ele acha de enviar um polyfill de onda de choque no núcleo.

Não estou dizendo que é um caso de uso que as pessoas nunca vão querer fazer, posso entender o desejo de fazer isso, estou simplesmente dizendo que não se encaixa no padrão ngModel e exige que adicionemos algum material extra para suporta todos os navegadores de destino, portanto, quebra a estrutura dessa maneira.

Qual é o problema de usar módulos de terceiros para isso?

Este polyfill não requer flash.

@jreading isso não é uma polyfill, e é usado para enviar com um flash uploader, ele provavelmente ainda tem algum lugar.

O que ele está fazendo é confiar na API File, que não está disponível em todos os navegadores de destino e, portanto, é problemática para o angular 1.x core.

Sem essa API, você não tem como chegar ao blob do arquivo sem algo como shockwave.

Ele usa iframes em vez de flash, você pode estar pensando nisso . Em vez de discutir a semântica, que tal um roteiro? Vamos começar com ng-change na entrada de arquivo para navegadores compatíveis com API de arquivo.

@jreading, infelizmente, isso não ajuda os navegadores que não são compatíveis com a API, o que inclui o IE9, que ainda é compatível. Não podemos enviar uma API que funcione no navegador compatível A, mas não compatível com o navegador B no núcleo, sem qualquer solução alternativa para as pessoas que dependem do suporte do IE9. E não, um iframe não expõe o conteúdo de um arquivo como um blob e o torna carregável. Hnnggggg.

Existem soluções para isso em módulos de terceiros, que os aplicativos podem usar se acharem que são adequados. Colocar isso no núcleo A) dificulta os módulos de terceiros e B) falha em oferecer suporte a todos os navegadores de destino, então isso é um problema.

Isso é só minha opinião, talvez o Igor ou outra pessoa discorde, mas não acho que seja a abordagem certa aqui.

Qual é o problema de usar módulos de terceiros se eles funcionam para você e você precisa deles?

Nunca realmente deu a entender que um blob precisava estar disponível para o controlador. Estou indo para um limb, mas o maior caso de uso que vejo é a capacidade de saber quando a entrada do arquivo mudou e a capacidade de enviá-lo para um endpoint restante, que está disponível com esta solução iframe ou API de arquivo e angular hacks.

Módulos de terceiros são a única forma de aprimoramentos agressivos como minha postagem no blog (sem upload para você!), Mas eu poderia simplesmente contornar a questão e perguntar "qual é o problema de ter uma API melhor para navegadores modernos?"

"qual é o problema de ter uma API melhor para navegadores modernos?"

Esse argumento é fraco porque não leva em consideração o custo de oportunidade; há muitas outras coisas nas quais nós (a equipe principal) podemos trabalhar.

É justo. Parece uma lacuna enorme e um fruto mais baixo.

A questão aqui não é como fazer isso funcionar com o ngModel. Acho que o ngModel poderia expor o FileList do campo de entrada para o escopo, mas na outra direção, permitiríamos apenas a configuração do modelo como nulo / indefinido para ser suportado. os analisadores / formatadores provavelmente não fariam nada e os validadores apenas fariam coisas simples, como verificar a presença ou ausência de arquivos.

O problema é (como foi mencionado antes) que sem o suporte à API de arquivo fazer isso corretamente é inviável para o núcleo, já que nossa linha de base é o IE9 e o polyfilling está fora de questão para o núcleo.

Além disso, tentar lidar com essa entrada de uma forma que não seja compatível com navegadores diferentes apenas torna mais difícil para soluções de terceiros, que agora precisam lutar / desativar / contornar a solução central.

soluções não essenciais que lidam com isso já existem e foram mencionadas nesta discussão do problema, bem como na edição anterior

Há muitas outras coisas que têm um impacto maior que queremos que sejam realizadas. Eu entendo que este é um caso relativamente comum, mas ainda não ouvi por que as soluções existentes não são suficientes.

Será que parte da energia que está sendo colocada nesta discussão pode ser redirecionada para a melhoria das soluções existentes, se necessário, ou para a criação de uma nova solução superior às existentes?

Vou fechar isso assim como fechamos o número 1236. O Angular 2 está sendo construído para suportar navegadores modernos e com esse suporte de arquivo estará facilmente disponível.

Eu simplesmente quero saber quando o evento de mudança acontece para que eu possa acessar o elemento diretamente e pegar as informações do arquivo e fazer upload via AJAJ.

@bjoshuanoah então para que você precisa do ngModel? Basta vincular um ouvinte de evento ao input = p

@caitp quero controlar tudo no controlador e não com uma diretiva.

Se eu colocar ng-change = "uploadFile ({$ event: $ event})"

Posso ter $ scope.uploadFile (event) em meu controlador. e lidar com isso lá.

Meu caso de uso específico é este: fazer upload do arquivo para s3, aplicar a url ao meu modelo.

em vez disso, tenho que entrar no escopo para fazer a mesma coisa. Muito irritante:

<input name="highRes" scope="{{contentOptions.currentValue}}" key="value" type="file" onchange="angular.element(this).scope().setFile(this)">

Eu gostaria que alguém acabasse com esse problema. para que possamos seguir em frente :)

Em 25 de julho de 2014, às 9h22, Brian < [email protected] [email protected] > escreveu:

Eu simplesmente quero saber quando o evento de mudança acontece para que eu possa acessar o elemento diretamente e pegar as informações do arquivo e fazer upload via AJAJ.

-
Responda a este e-mail diretamente ou visualize-o em Gi tHubhttps: //github.com/angular/angular.js/issues/1375#issuecomment -50171714.

+1

+1

+1000000000000000

+1

+1

+1

+1

+100500

+1
Não sei por que Ajax é um problema. Pode-se desejar carregar dados de um arquivo csv na máquina local em um modelo Angular. Se o ng-change funcionasse na entrada do arquivo dentro do Angular, isso seria fácil; atualmente , não é . Este cenário não requer Ajax ou uma API de servidor. Eu também não tenho certeza por que isso está fechado.

Minha solução alternativa atual é fazer o seguinte

 input(type="file", onchange="angular.element(this).scope().onFileSet(this.files)")

e no meu controlador apenas tenho algo como

$scope.onFileSet = function(files) { 
// work your magic here 
}

Mesmo assim, eu sinto que estou bastardizando o angular como uma ferramenta. Qualquer ideia de como fazer isso de uma forma mais angular seria muito apreciada.

:coração coração:

Aqui está um veleiro:: veleiro:

@samccone O scope () não está disponível quando o modo de depuração está desligado?

@geetsce Correto (em 1.3.x e posterior)

bem, em 1,2 terreno está tudo bem.

@Narretz você tem uma solução melhor tho?

Isso funciona para mim, é inspirado em https://jasonturim.wordpress.com/2013/09/01/angularjs-drag-and-drop

<input type="file" multiple="multiple" data-dbinf-on-files-selected="chooseAFunctionName(selectedFileList)">
<script>
/**Directive to propagate selected files from an HTML input element with type="file"
 * to the surrounding AngularJS controller.
 */
myApp.directive('dbinfOnFilesSelected', [function() {
    return {
        restrict: 'A',
        scope: {
              //attribute data-dbinf-on-files-selected (normalized to dbinfOnFilesSelected) identifies the action
              //to take when file(s) are selected. The '&' says to  execute the expression for attribute
              //data-dbinf-on-files-selected in the context of the parent scope. Note though that this '&'
              //concerns visibility of the properties and functions of the parent scope, it does not
              //fire the parent scope's $digest (dirty checking): use $scope.$apply() to update views
              //(calling scope.$apply() here in the directive had no visible effect for me).
            dbinfOnFilesSelected: '&'
        },
        link: function(scope, element, attr, ctrl) {
            element.bind("change", function()
            {  //match the selected files to the name 'selectedFileList', and
               //execute the code in the data-dbinf-on-files-selected attribute
             scope.dbinfOnFilesSelected({selectedFileList : element[0].files});
            });
        }
    }
}]);

myApp.controller('myController', ['$scope', function($scope) {
    $scope.chooseAFunctionName = function (filelist) {
        for (var i = 0; i < filelist.length; ++i) {
            var file = filelist.item(i);
            //do something with file; remember to call $scope.$apply() to trigger $digest (dirty checking)
            alert(file.name);
           }
    };
}]);
</script>

+1

+1

Isso não vai acontecer ... Deixa pra lá, deixa pra lá ...

+1

Como @samccone disse,

input(type="file", onchange="angular.element(this).scope().onFileSet(this.files)")

Esta não é a maneira Angular de fazer as coisas. É estranho.

+1

+1

+1

ei @caitp @Narretz se vocês gostariam que eu pudesse fazer um PR para isso para o branch 1.2x, deixe-me saber se isso é algo que você deseja adicionar ou não. Eu entendo as preocupações de segurança e a falta de suporte para vários navegadores no que diz respeito ao acesso ao objeto de arquivo real, no entanto, parece que o suporte básico para detectar quando uma entrada de arquivo foi alterada (passando no evento original) seria um gancho suficiente para as pessoas fazerem sua mágica.

Obrigado novamente por tudo que você faz: palm_tree:

+1

+1

+1

+1

+1

ng-file-upload está funcionando muito bem.

+1 para @neokyol !! Funciona muito bem!

este recurso comum deve estar por padrão no framework

útil

+1

+1

+1

+1

+1

isso funcionou para mim, pode ajudar

angular.module('app', [])
  .controller('MainCtrl', MainCtrl)
  .directive('fileChange', fileChange);

  function MainCtrl($scope) {
    $scope.upload = function () {
      // do something with the file
      alert($scope.file.name);
    };
  }

  function fileChange() {
    return {
      restrict: 'A',
      require: 'ngModel',
      scope: {
        fileChange: '&'
      },
      link: function link(scope, element, attrs, ctrl) {
        element.on('change', onChange);

        scope.$on('destroy', function () {
          element.off('change', onChange);
        });

        function onChange() {
          ctrl.$setViewValue(element[0].files[0]);
          scope.fileChange();
        }
      }
    };
  }
<div ng-app="app" ng-controller="MainCtrl">
  <input type="file" file-change="upload()" ng-model="file">
</div>

http://plnkr.co/edit/JYX3Pcq18gH3ol5XSizw?p=preview

+1

+1

+1

+1

+1000000000000000000000000

+1

+1

@dciccale você pode fornecer um exemplo de plunker.

+1

+1

+1 Deve haver uma diretiva embutida na biblioteca central para isso. É bem ridículo

+1

+1
o recurso está programado para um dos próximos lançamentos?

+1

+1

Como fazer isso em projetos onde $ scope nunca está sendo injetado no controlador. Estou usando o laravel angular que usa a forma GULP e ES6 de declarar controladores.

ie

class TestController{
    constructor(API){
        'ngInject';
        this.API = API
    }

    $onInit(){
        this.file = null;
    }
    upload() {
        console.log(this.file)
    }
    fileChanged(elm) {
        console.log('hey')
        this.file = elm.file;
        this.$apply();
    }
}

export const TestComponent = {
    templateUrl: './views/app/components/test/test.component.html',
    controller: TestController,
    controllerAs: 'vm',
    bindings: {}
}

Eu encontrei uma solução em torno, eu acredito. http://stackoverflow.com/questions/38449126/how-to-set-up-ng-file-upload-in-laravel-angular-project/38486379#38486379

+1

@ntrp @guruward @coli @lgersman @jgoldber @Siyfion
Como você corrigiu a validação para
Minha validação:
this.catalougeForm = this.catalougeFormBuilder.group ({
catalougeIconName: ['', Validators.required]
});
Html:
(alterar) = "changeListener ($ event)">

Meu validador está considerando o valor catalougeIconName como vazio / nulo após o upload.
A imagem está sendo enviada, mas o validador não está funcionando

Alguma atualização sobre isso?

Alguma atualização?

Esta página foi útil?
0 / 5 - 0 avaliações