Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: JS: Miksi vain viimeinen latauspalkki päivittyy?

Sivun loppuun

dartvaneri [17.06.2016 11:27:49]

#

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) {

	}
});

Grez [17.06.2016 11:44:09]

#

Nopealla googletuksella löytyi esim seuraava:
http://stackoverflow.com/questions/6728750/html5-file-uploading-with-multiple-progress-bars

Metabolix [17.06.2016 12:06:07]

#

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.

dartvaneri [17.06.2016 15:44:50]

#

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?

Grez [17.06.2016 16:19:50]

#

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"?

Metabolix [17.06.2016 16:28:25]

#

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.

dartvaneri [20.06.2016 05:49:13]

#

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.

Grez [20.06.2016 07:56:39]

#

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.

The Alchemist [20.06.2016 12:26:15]

#

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.

jlaire [20.06.2016 20:43:53]

#

The Alchemist kirjoitti:

Tuossa ei missään palauteta funktiota funktiosta

... paitsi Metabolixin ratkaisussa, johon tämä line-by-line oli suora vastaus.

Metabolix [20.06.2016 21:25:34]

#

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.

dartvaneri [11.07.2016 14:42:15]

#

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)?

dartvaneri [29.07.2016 13:31:14]

#

Kellään ideoita?

Metabolix [29.07.2016 17:57:26]

#

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ä.

dartvaneri [30.07.2016 22:00:11]

#

Okei, tutkiskelin vähän File APIa, ja se näyttäoso ratkaisevan ongelmani, leikimään en rupea.

Kiitos!


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta