Tervehdys!
Teen tiedostojen lautauspalikkaa(upload) järjestelmääni. Tarve olisi saada useita tiedostoja latautumaan yhtäaikaa ja kaikille oma latauspalkki. Tiedostojen lataaminen sinällään ei aiheuta ongelmaa, eikä yhden latauspalkin käyttäminen, mutta kun tehdään useta latauksia, niin pitäis saada jokainen päivittämään omaa palkkiansa.
Käytän lomakkeen lähettämiseen ajaxForm palikkaa. ajaxFormissa on funktio uploadProgress, jossa pystytään päivittämään palkkia. Ongelma on siis se, että pitäsi jollain tavalla saada välitettyä kyseiselle funktiolle tieto siitä, että mitä palkkia sen pitää päivittää. Nykyisellään se jatkaa päivittämistä viimeisimmäksi lisättyyn palkkiin ja pysäyttää kaiken muun.
Onko ideoita, miten ongelman ratkaisisi? Ei oo pakko käyttää ajaxFormia.
Tässä koodi, joka lähettää lomakkeen.
$('#AttachmentForm').ajaxForm({ beforeSend: function() { $("#Attachments").append($("#FileUploadInput").val()+'\ <div class="Progress" id="Prog'+ProgressID+'">\ <div class="Bar" style="width:0%;"></div>\ <div class="Percent">0%</div>\ </div>\ '); ProgressID++; }, uploadProgress: function(event, position, total, percentComplete) { var percentVal = percentComplete + '%'; $("#Prog"+ProgressID+" .Bar").width(percentVal); $("#Prog"+ProgressID+" .Percent").html(percentVal); }, complete: function(xhr) { } });
Nopealla googletuksella löytyi esim seuraava:
http://stackoverflow.com/questions/6728750/html5-file-uploading-with-multiple-progress-bars
Ongelma on muuttujan sitomisessa. Käytät funktioissasi ulkopuolista muuttujaa ProgressID, jonka arvo ilmeisesti muuttuu välillä. Funktioihin ei siis jää muuttujan arvo funktion luomisen hetkellä, vaan funktioihin jää juurikin viittaus kyseiseen muuttujaan. Itsehän olet hyödyntänyt tätä beforeSend-funktiossa, joten ”turha itkeä”, kun sama ominaisuus pätee myös seuraavassa funktiossa. Sinun pitää jotenkin tallentaa muuttujan arvo kunkin latauksen kohdalla erikseen.
(Edit: En huomannut ensin, että ProgressID:tä kasvatetaan uploadSend-funktiossa. Alla on korjattu vastaus.)
Ongelma: Ohjelmassa on vain yksi muuttuja, joka jää luotavaan funktioon:
var ProgressID = 0; var f = function() { ProgressID++; return function() { return ProgressID; } } var x = f(), y = f(), z = f(); print(x(), y(), z()); // 3 3 3, sama ProgressID-muuttuja.
Ratkaisu: Kopioidaan muuttuja erikseen sisempää funktiota varten.
var NextProgressID = 0; var f = function() { var ProgressID = NextProgressID++; return function() { return ProgressID; } } var x = f(), y = f(), z = f(); print(x(), y(), z()); // 0 1 2, eri ProgressID-muuttuja kaikilla.
Yksinkertaisinta tapauksessasi on siirtyä ajaxForm-funktiosta pelkkään ajaxSubmit-funktioon, jolloin joka lähetyskerralla luodaan uudet käsittelijät (beforeSend ja uploadProgress) ja ProgressID-muuttujan kopiointi on helppoa:
var NextProgressID = 0; $('#AttachmentForm').submit(function() { var ProgressID = NextProgressID++; $(this).ajaxSubmit(/* Asetukset, kuten edellä, paitsi ilman ProgressID++:aa. */); return false; });
En tykkää toteutuksista, joissa haetaan $:lla toistuvasti uudestaan elementtejä, vaan pyrkisin ehkä säilömään viittauksen elementtiin jossain muuttujassa ja käyttämään sitä ProgressID:n sijaan. Tämä ei kuitenkaan vaikuta olennaisesti itse ongelmaan tai sen ratkaisuun.
Kiitos Metabolix!
Hyvin loogista, kun kysessä ei ole line by line suoritettava kieli.
Edit.
Metabolix kirjoitti:
En tykkää toteutuksista, joissa haetaan $:lla toistuvasti uudestaan elementtejä, vaan pyrkisin ehkä säilömään viittauksen elementtiin jossain muuttujassa ja käyttämään sitä ProgressID:n sijaan. Tämä ei kuitenkaan vaikuta olennaisesti itse ongelmaan tai sen ratkaisuun.
Onko tälle jotain perustetta, vai vain mielipide?
dartvaneri kirjoitti:
kun kysessä ei ole line by line suoritettava kieli.
Mitä tämä ikäänkuin tarkoittaa? Mitkä kielet sitten ovat "line by line suoritettavia"?
dartvaneri kirjoitti:
Hyvin loogista, kun kysessä ei ole line by line suoritettava kieli.
Greziä kompaten: itsekään en keksi, millaisella kielellä sitten koodisi toimisi.
Jos alkuperäinen arvo jäisi jokaiseen funktioon, ProgressID pysyisi koko ajan samana, tulisi monta samannimistä palkkia, homma olisi ihan sekaisin.
Jos taas jokaiseen funktioon jäisi oma kopio muuttujasta, ProgressID ensimmäisessä funktiossa kasvaisi mutta päivitysfunktiossa olisi aina alkuperäinen, jolloin vain ensimmäinen latauspalkki päivittyisi.
Jos jotenkin maagisesti koko updateProgress-funktio luotaisiin aina uudestaan beforeSend-funktion suorituksen jälkeen (mikä olisi todella ihmeellistä), ProgressID olisi yhden liian suuri (juuri korotettu), ja mahdollinen päivitys kohdistuisi siis vasta seuraavalla kerralla lisättävään palkkiin.
Oliko mielessäsi vielä jokin muu tapa, miten koodi voisi (jossain kielessä) edetä?
dartvaneri kirjoitti:
Metabolix kirjoitti:
En tykkää toteutuksista, joissa haetaan $:lla toistuvasti uudestaan elementtejä, vaan pyrkisin ehkä säilömään viittauksen elementtiin jossain muuttujassa ja käyttämään sitä ProgressID:n sijaan. Tämä ei kuitenkaan vaikuta olennaisesti itse ongelmaan tai sen ratkaisuun.
Onko tälle jotain perustetta, vai vain mielipide?
Muuttujat ehkäisevät virheitä. Jos koodiin tulee myöhemmin muutoksia, voi helposti jäädä jostain kohti valitsin (tai muuttuja) vaihtamatta. Valitsinten kohdalla tästä ei tule mitään virheilmoitusta, kun jQuery vain palauttaa tyhjän joukon. Muuttujan tai jäsenen kohdalla taas tulisi virheilmoitus, että arvoa ei ole määritelty tai ei ole objekti.
Lisäksi tulosten tallentaminen on sikäli tehokkaampaa, että ei tarvitse tehdä toistuvasti suhteellisen hidasta hakua valitsimilla vaan tulos on valmiina. Toisaalta pitää varoa, ettei jätä mihinkään roikkumaan viittauksia jo poistettuihin elementteihin, jottei muistia kulu turhaan. Toki parin latauspalkin kohdalla nämä ovat pieniä murheita.
Pientä sekoilua... Line by line suoritettavalla koodilla tarkoitin koodia, joka suoritetaan kertaalleen rivi riviltä ja that's it. JS koodissahan on tapahtumakäsittelijöitä, joiden kautta siihen koodin palataan hyvinkin usein.
En tarkoittanut, että se(koodini) toimisi jollain muulla kielellä, eihän se toimi, mutta kun esimerkiksi PHP:ssä ei oo tullut koskaan vastaan omaa, eikä kenenkään muunkaan, tarvetta, missä pitäisi saada palautettua funktio funktiosta, mikä kyllä PHP:llä on mahdollista, niin ei kyseistä ongelmaa ole tullut.
Jos voisin, soisin seuraavan rivin olevan kirjoittamatta:
dartvaneri kirjoitti:
Hyvin loogista, kun kysessä ei ole line by line suoritettava kieli.
dartvaneri kirjoitti:
Pientä sekoilua... Line by line suoritettavalla koodilla tarkoitin koodia, joka suoritetaan kertaalleen rivi riviltä ja that's it.
Käytännössä sellaista ohjelmointikieltä ei taida olla olemassakaan, tai ainakaan sellainen ei ole kovin käyttökelpoinen.
Käytännössä kaikissa ohjelmointikielissä, jotka muuten olisivat "line by line", on funktioita, looppeja, yms. Tai jos ei niitä, niin ainakin hyppykäskyjä joilla em. toiminnallisuudet voi toteuttaa.
dartvaneri kirjoitti:
Pientä sekoilua... Line by line suoritettavalla koodilla tarkoitin koodia, joka suoritetaan kertaalleen rivi riviltä ja that's it. JS koodissahan on tapahtumakäsittelijöitä, joiden kautta siihen koodin palataan hyvinkin usein.
En tarkoittanut, että se(koodini) toimisi jollain muulla kielellä, eihän se toimi, mutta kun esimerkiksi PHP:ssä ei oo tullut koskaan vastaan omaa, eikä kenenkään muunkaan, tarvetta, missä pitäisi saada palautettua funktio funktiosta, mikä kyllä PHP:llä on mahdollista, niin ei kyseistä ongelmaa ole tullut.
Tuossa ei missään palauteta funktiota funktiosta ja sellaiset tilanteet ovat aika harvinaisia javascriptissäkin. Lambda-funktioiden käyttö sen sijaan on yleistä melkein kielestä riippumatta vaikka kontekstisäännöt vaihtelevatkin kielestä toiseen ja php:n tapauksessa jopa käytetystä notaatiosta toiseen.
The Alchemist kirjoitti:
Tuossa ei missään palauteta funktiota funktiosta
... paitsi Metabolixin ratkaisussa, johon tämä line-by-line oli suora vastaus.
Ongelman kannalta ei ole merkitystä, mitä funktiolle tarkalleen tehdään, palautetaanko, tallennetaanko muuttujaan tai annetaanko parametrina jollekin kirjastolle. Olennaista on, että alkuperäisessä koodissa luodaan yksi funktio, jossa on näin ollen viittaus yhteen ja samaan ProgressID-muuttujaan, kun taas ratkaisussa luodaan uusi funktio jokaisella lomakkeen lähetyskerralla, jolloin saadaan joka lähetykselle eri ProgressID.
Jatkan samasta aiheesta:
Määritän inputille boolean attripuutin multiple, jolloin voin ladata useamman tiedoston kerralla. Onko jollakin lailla mahdollista saada näille jokaiselle tiedostolle oma latauspalkki ja jos ei, niin kuinka saada ne kaikki yhteen palkkiin, niin että se palkki ei sahailis edestakaisin(ilmeisesti tiedoston vaihtuessa)?
Kellään ideoita?
Kylläkin kirjaston esimerkki näyttää ihan oikein yhden palkin koko lataukselle. (Testattu kirjoitushetkellä Arch Linuxista löytyvillä Chromiumilla ja Firefoxilla.) Mitään hyppimistä ei pitäisi tulla, eli sen olet koodannut ihan itse.
Leikisti erilliset palkit voi tehdä niin, että pyynnön alussa katsoo inputin files-taulukosta tiedostojen nimet ja koot ja täyttää palkit järjestyksessä oikealla nopeudella.
var x = uploaded for (var i = 0; i < tiedostoja; ++i) { if (x <= 0) { palkki[i] = 0 } else if (x < koko[i]) { palkki[i] = x / koko[i] } else { palkki[i] = 1 } x -= koko[i] }
Oikeasti erillisiä palkkeja varten pitäisi lähettää jokainen tiedosto erikseen, mikä kyllä onnistuu uusilla tiedostorajapinnoilla mutta vaatii lisätyötä.
Okei, tutkiskelin vähän File APIa, ja se näyttäoso ratkaisevan ongelmani, leikimään en rupea.
Kiitos!
Aihe on jo aika vanha, joten et voi enää vastata siihen.