[CSS][JS] Jak zmienić atrybut display Javascriptem?

0

Witam,
Posiadam tabelke, w której chce ukrywać dane -ki kliknięciem.
Wszystko działa fajnie, z tym że ja chce mieć dane -ki domyślnie schowane.
Zatem nadałem klasie .first display:none;
Niestety wtedy moje togglowanie nie działa. Mogę klikać na tabele by sie jedna komóreczka chowała, bądź ukrywała, ale nic sie nie pojawia.
Jak zatem to zrobić? Nie za bardzo chcę stosować windows.onload, bo mam dużo tdków i przymuli na początku wczytywanie strony.

Kod HTML:

<style type="text/css">
.first {
display:none;
}
</style>
  <script type="text/javascript">
    function ToggleIdHide(id) {
       var e = document.getElementById(id);
       if(e.style.display == '')
          e.style.display = "none";
       else
          e.style.display = '';    }
	
		</script>


<table onclick = "ToggleIdHide('first')" border = 1><tr><td class = "first" id = "first">1</td><td>2</td><td>3</td></tr><tr><td>4</td><td>5</td><td>6</td></tr></table>
0

może zamiast none użyj hide

0

atrybut display, nie ma wartości none. Ma hide, block itd.<- przejęzyczenie
Prawidłowo: atrybut display, nie ma wartości hide. Ma none, block itd.
http://www.signs.pl/html/s/display.php
Zatem, czekam na wypowiedzi innych ;)

0

Widzę, że @Dyspenser palnął głupstwo, a Ty, @tMbRaga, chyba się "przejęzyczyłeś". Atrybut display nie ma wartości hide. Ma natomiast block, none i parę innych.

Tutaj MUSISZ użyć jakiejś konkretnej wartości, by nadpisać to, co masz w stylach. Gdyby nie te style, to zadziałałoby ustawienie display na '' (po prostu: wartość pusta przywróciłaby domyślną). Użyj więc 'table-cell'. Mogą być jednak problemy z kompatybilnością w przeglądarkach ze słabszymi silnikami renderującymi. Z tego co kojarzę, problemy mogą być nawet jeszcze w IE7.

Możesz jednak zrobić inaczej. Zamiast manipulować CSS-em przez JavaScript, niech JavaScript dodaje i usuwa jakąś klasę. Masz klasę "first", ale ona wydaje mi się bez sensu. Jeśli ma to być ogólne i logiczne, to nazwij ją "hidden" i daj jej w CSS display: none. Następnie, daj tę klasę tym elementom, które mają być na początku schowane. Kod JavaScript powinien patrzeć, czy dany element ma klasę "hidden", czy nie (należy użyć własności className). Jeśli ma, to powinien ją usunąć (wtedy element się pojawi). Jeśli nie ma klasy "hidden", to trzeba ją dać, wtedy element się ukryje.

Jeśli komórki tabeli nie mają innych klas i użyłbyś tylko tego "hidden", to będzie to bardzo proste. Wystarczy sprawdzać i ustawiać className wprost (e.className === 'hidden'; e.className = '' itp.). Jeśli klas jest więcej, to będziesz musiał sprawdzać, czy wśród nich znajduje się 'hidden' i będziesz musiał usuwać tylko tę jedną klasę (wtedy najlepiej użyć wyrażeń regularnych -- chyba że masz np. jQuery, której funkcje addClass/hasClass zrobią to za Ciebie).

0

Tak przejęzyczyłem się.

Ta klasa first i cała ta bezsensowna tabelka miała zobrazować problem.

Część z mojej docelowej tabelki wygląda tak:
<td class = "f_mies">mies.</td><td class = "f_rob">rob.</td><td class = "d_przychod">przychód</td><td class = "d_marza">marża</td><td class = "d_prognoza">prognoza</td><td class = "d_marza2">marża %%</td><td class = "d_koszyk">koszyk (zł/prod)</td><td class = "d_trans">ilosc transak.</td><td class = "d_mag">stan mag.</td><td class = "d_zadluzenie">zadłużenie</td>

Jak widać mają one już klasy... więc dodawanie klasy raczej odpada.

Nie można jakoś zmusić JS, żeby miał wyższy priorytet niż CSS?
Nie wiem, może głupio gadam...

0

JS ma wyższy priorytet niż arkusze stylów CSS. Ale gdy ustawiasz display na '' to mówisz, że JS wypada z gry i prosisz przeglądarkę, by wróciła do poprzedniej wartości display. Tej ustawianej przez arkusze stylów. Zauważ, że gdy za pomocą JavaScriptu przypisujesz jakąś wartość do display, to nadpisuje ona to, co jest w stylach. Tyle że przypisać możesz tylko 'none', bo z 'table-cell' mogą być problemy (sprawdzałeś?).

Dodawanie klasy NIE odpada. To standardowa praktyka, jeden z JavaScriptowych "wzorców projektowych". Tyle że jest to odrobinę bardziej hardcorowe niż absolutne podstawy JavaScriptu. Choć w zasadzie... niekoniecznie. Proste wyrażenia regularne i proste, krótkie funkcje (stąd):

function hasClass(ele,cls) {
	return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}

function addClass(ele,cls) {
	if (!this.hasClass(ele,cls)) ele.className += " "+cls;
}

function removeClass(ele,cls) {
	if (hasClass(ele,cls)) {
		var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
		ele.className=ele.className.replace(reg,' ');
	}
}

Jako pierwszy parametr podajesz im element, na którego atrybucie class chcesz działać. Jako drugi parametr -- klasę, którą chcesz usunąć/dodać/sprawdzić jej obecność. Te funkcje nie dbają idealnie o spacje w atrybucie className, ale to Ci nie powinno przeszkadzać (napisałem szybkie funkcje, które o to dbają, ale są znacznie bardziej skomplikowane, a ja jeszcze ich nie open source'owałem).

0

No właśnie nie wiem jak z tym JS-em jest.
Ustawiłem ręcznie w CSS-ie wartość: table-cell, block itd.
Spróbowałem ją odczytać poprzez JS i mimo to otrzymałem ''.

EDIT:
Dodaje mi klase i chowa, ale już nie chce usuwać. removeClass się nie wykonuje, bo hasClass zwraca false. Czy to właśnie o ten problem chodziło ze spacją? Bo teraz hidden jest drugą klasą, jak się ją doda.

Drugi problem. Moja tabela to ponad 2000 komórek. Strasznie wolno to działa. Kilka sekund.
W tabeli posiadam po kilka zestawów kolumn, które chciałbym schować. Może jakoś pogrupować kolumny? Bo jeżdzenie po td to porażka.

if(hasClass(e[i],\'hidden\'))
{
    removeClass(e[i],\'hidden\');									
}
else
{
    addClass(e[i],\'hidden\');					
}
0

@tMbRaga:
To jest właśnie jeden z tych momentów, gdy stosunkowo proste rzeczy wydają Ci się trudne, ponieważ nie masz dogłębnej i w miarę pełnej wiedzy z dziedziny JS i CSS.

Za pomocą element.style możesz manipulować stylami elementu: dodawać nowe (będą silniejsze od zwykłych stylów z arkusza CSS), zmieniać je, a potem usuwać. Ale cały czas manipulujesz stylami, które dodałeś z poziomu JS, za pomocą element.style. Tylko je możesz odczytać w ten sposób. W element.style nie są widoczne tzw. obliczone style, które wynikają ze wszystkich reguł CSS dotyczących danego elementu.

Używając zupełnie innego sposobu (document.styleSheets) możesz manipulować regułami dołączonymi przez arkusze stylów. Czyli jeśli w jakimś arkuszu masz reguły "p { margin: 15px 0; }" oraz ".error {color: red; }", to za pomocą document.styleSheets możesz odczytać te reguły.

Z kolei jeśli chcesz po prostu zobaczyć np. jaki kolor czcionki ostatecznie ma dany element -- bo przecież jedna reguła może mówić, że ma zielony, druga, że ma czerwony, a obie może nadpisać jakiś zupełnie inny styl mówiący, że ma to być żółty -- to musisz sięgnąć po tzw. obliczone style. Czyli te, które ostatecznie dotyczą danego elementu, po uwzględnieniu wszystkich reguł, wszystkich arkuszy stylów, atrybutu style oraz element.style. Te informacje są dostępne poprzez window.getComputedStyle (i odpowiedniki w innych przeglądarkach).

edit: A może zapodaj po prostu link do całego kodu? Wtedy będzie można zerknąć i zobaczyć co jest nie tak (nie gwarantuję, że znajdę na to czas i chęci).

0
bswierczynski napisał(a)

Widzę, że @Dyspenser palnął głupstwo, a Ty, @tMbRaga, chyba się "przejęzyczyłeś". Atrybut display nie ma wartości hide. Ma natomiast block, none i parę innych.

Masz rację wyskoczyłem na szybko i szczerze pisząc nie wiem co miałem wtedy na myśli (jak widać chyba nie css). Przyznaję się, że palnąłem :/

0

@tMbRaga: Może nie na temat, ale radzę ci używać '===' zamiast '==', i nawiasów klamrowych w pętlach :P

0
Perykles napisał(a)

@tMbRaga: Może nie na temat, ale radzę ci używać '===' zamiast '==', i nawiasów klamrowych w pętlach :P

A to odnośnie jakiego kodu? Podaj także argumenty, dlaczego tak, a nie inaczej.

EDIT:
Tabelke i problem dodałem w tym nowym temacie:
http://4programmers.net/Forum/659184?f=3#id659184
Nie kontynuowałem tego, bo problem nie dotyczy już atrybutu display, tylko samej tabelki.

0

@tMbRaga:
Np. odnośnie kodu z pierwszego posta w tym temacie.

Operator == jest lipny, bo próbuje "dopasować" typy. Tak naprawdę to nie tyle dopasować, co przeprowadzić jakieś dziwne konwersje na operandach (fachowo zwie się to koercją).

Skutek? Zobacz na poniższą serię wyrażeń z operatorem == i wyniki, jakie zwracają:

0 == "03" // true
"" == false; // true
null == false // false
"\r\n" == 0 // true

// Tablice generalnie mają wartość logiczną true,
// więc new Boolean([]) daje true, a new Boolean(![]) daje false.
// Ale zobacz na poniższe dyrdymały...
[] == ![] // true
[] == false; // true

W specyfikacji, działanie operatora == jest opisane w bodajże kilkunastu podpunktach. Są one niemożliwe do zapamiętania.

Operator === nie sprawia takich problemów. Najpierw musi się zgadzać typ, potem zawartość. I tyle (no, jedyny wyjątek jest taki, że NaN === NaN zwróci false, bo taka jest definicja NaN). Dodatkowo, === jest oczywiście szybsze niż ==, bo nie musi wykonywać koercji typów.

Dlatego jak sprawdzasz, czy gdzieś siedzi np. konkretny string, to użyj ===. Nie ma powodu, żebyś użył ==. Oszczędność jednego znaku jest nieistotna, tego operatora nie używa się aż tak często.

Narzędzia sprawdzające jakość kodu, np. JSLint, zgłaszają każde użycie == jako potencjalny błąd.

Co do klamer, to argumentacja jest chyba jasna, choć nie jest ona już tak bezwzględnie prawdziwa, tj. zależy trochę od preferencji. Używanie klamer ZAWSZE zwiększa spójność, bo każdy blok kodu jest zawarty w klamrach. Gdy do bloku składającego się z jednej instrukcji dodaje się kolejną, to nie trzeba pamiętać o klamrach, bo one już tam są. Widziałem przynajmniej kilka razy, jak ktoś zapomniał dodać klamry i zastanawiał się, czemu jego if wykonuje się dziwnie. Albo: czemu nie wykonują się wszystkie instrukcje z jego pętli for. Z klamrami nie ma takich problemów. Ja zawsze ich używam.

0

Dzięki za wyjaśnienie teraz rozumiem.
Moim głównym językiem w którym tworzę aplikację to C i C++.
Tam kontrola typów wygląda całkiem inaczej niż w JS czy PHP. Deklaracje, rzutowania static_cast etc.
Stąd moje przyzwyczajenia.

Odnośnie klamer to już osobiste preferencje, nigdy nie miałem problemu z tym co przestawiłeś bswierczynski, a czasami jak chce by kod zajmował jak najmniej miejsca to klamry pomijam.
... bo najbardziej lubię klamry w oddzielnych liniach.

Za to kilka razy się zrobiłem w ten sposób:

if (warunek);
{
 // kod wykonywany (a w sumie to nie wykonywany ;P)
}
0
tMbRaga napisał(a)

Tam kontrola typów wygląda całkiem inaczej niż w JS czy PHP. Deklaracje, rzutowania static_cast etc.
Stąd moje przyzwyczajenia.

Przyzwyczajenia to raczej do tego, że w CPP i innych językach masz tylko operator == i to on jest tym właściwym. W JavaScripcie, jeśli chcesz mieć kontrolę typów bardziej restrykcyjną, bardziej w stronę C++, to powinieneś właśnie używać ===. Choć w JavaScripcie i tak nie masz kontroli typów w czasie kompilacji, to bardzo dynamiczny język.

tMbRaga napisał(a)

Odnośnie klamer to już osobiste preferencje, nigdy nie miałem problemu z tym co przestawiłeś bswierczynski, a czasami jak chce by kod zajmował jak najmniej miejsca to klamry pomijam.
... bo najbardziej lubię klamry w oddzielnych liniach.

No, jeśli ktoś poszedł już w "zawsze klamry", to raczej powinien pisać pierwszą klamrę w tej samej linii, co instrukcję warunkową, pętlę itd. Czyli nie od nowej linii.

Choć tak czy siak, w normalnych językach to kwestia preferencji. Niektórzy lubią bardzo dużo pionowego whitespace'u na ekranie. Dzisiejsze monitory wyświetlają tyle linii, że można być rozrzutnym. W końcu to, że dzisiaj mamy na ekranie nie 25, tylko 50 linii nie oznacza, że funkcje nagle powinny mieć 50 linii. Niech mają tyle logicznych linii co wcześniej. Dzisiaj po prostu możesz je udekorować whitespacem bez obawy o to, że skończy Ci się ekran.

Napisałem, że to, w której linii umieszczamy otwierającą klamrę, to kwestia preferencji w normalnych językach. Ale nie w JavaScripcie!

Wyobraź sobie, że JS to jeden z niewielu języków, w których w zasadzie ISTNIEJE "jedyny słuszny" sposób umieszczenia klamer ;). I mam dla Ciebie złą wiadomość: to nie jest umieszczanie otwierającej klamry w nowej linii.

Pewnie mi nie wierzysz i wcale Ci się nie dziwię. Zobacz jednak na poniższy przykład:

function fff()
{
  ...
  return
  {
     str: 'abc',
     num: 123
  };
}

Co ta funkcja robi? Zwraca jakiś obiekt z własnościami str oraz num, tak?

Nie.

Zwraca undefined. Bo zastosowano "złe klamry".

Wynika to z błędu języka. JavaScript posiada nieprzydatny, denerwujący mechanizm automatycznego wstawiania średników. To miał być ukłon dla tych, którym nie chce się pisać i/lub są początkującymi script-kiddiesami ;). Jak pominiesz średnik na końcu linii, to JavaScript sam Ci go dopisze, o ile ma to sens syntaktyczny.

Niestety, w przypadku instrukcji return -- ma. Możesz przecież napisać wewnątrz funkcji samo return, bez żadnej zwracanej wartości (daje się trochę we znaki to, że w JS-ie nie deklarujesz typu zwracanej wartości!). Więc język myśli, że chciałeś zrobić taki po prostu return bez niczego, bo masz jedną linię z samym słowem "return". Na końcu tej linii wstawiany jest automatycznie średnik, czyli instrukcja wygląda tak:

  return;
  {
     str: 'abc',
     num: 123
  };

(zauważ średnik zaraz za return)

Czyli funkcja po prosty wychodzi, nie zwracając nic (w JavaScripcie skutkuje to zwróceniem undefined). Co się dzieje dalej z tymi klamrami? Cóż, to już jest trochę popieprzone. Pomyślałby kto, że dalej stoi sobie po prostu literał obiektowy, ale obiekt idzie w próżnię. Tak nie jest ze względu na działanie analizatorów semantycznych (parserów) JavaScriptu. Klamry tworzą zwykły blok instrukcji. str i num są odczytywane jako... etykiety. Literały 'str' i 123 to po prostu wolnostojące literały. Przecinek zostaje separatorem. Innymi słowy: kosmos.

Nic takiego by się nie stało, gdyby użyć jedynego właściwego (niestety) w JavaScripcie położenia klamer:

function fff()
{
  ...
  return {
     str: 'abc',
     num: 123
  };
}

Specjalnie zmieniłem tylko klamrę przy return, żeby było widać, że to ona jest sprawcą bałaganu. Teraz już na końcu linii z return nie może zostać wstawiony średnik, bo to powodowałoby błąd. Więc nic złego się nie dzieje i funkcja zwraca obiekt -- tak, jak chcieliśmy.

Co gorsza, to wcale nie jest sytuacja hipoptetyczna. Obiekty w JavaScripcie zwraca się bardzo często.

Jest nawet specjalny JavaScriptowy wzorzec, bardziej wzorzec językowy niż projektowy. Zwie się to z angielskiego "revealing module pattern" i służy do budowania czegoś, co przypomina klasy z innych języków.

Wygląda to tak:

function MojaKlasa() {
  var wlasnoscPrywatna1,
      wlasnoscPrywatna2
  ;

  // na razie to tylko metody prywatne
  function foo() {
  }

  function bar() {
    ...
    baz(); // można wywoływać inne metody prywatne
    ...
  }

  function baz() {
  }

  // tu zwracamy obiekt z metodami, które będą publiczne
  return {
    foo: foo,
    renamedBar: bar
  };
}


// tworzymy instancję klasy i operujemy na jej metodach:
var mójObiekt = new MojaKlasa();
mójObiekt.foo();
mójObiekt.renamedBar(); 

// nielegalne: 
// mójObiekt.bar();
// mójObiekt.baz();

W JavaScripcie konstruktory zwracają po prostu gotowe obiekty za pomocą instrukcji return (jeśli return w konstruktorze zostanie pominięte, to konstruktor automatycznie zwróci this). W tym wzorcu wewnątrz konstruktora (jakby: wewnątrz definicji klasy) definiujemy tylko metody prywatne i to na nich operujemy. Na samym końcu konstruktora zwracamy za pomocą return obiekt zawierający te metody, które chcemy udostępnić na zewnątrz. Czyli te metody staną się prywatnymi. Możemy, ale nie musimy udostępnić metodę prywatną pod inną nazwą, tak jak to zrobiłem z baz -> renamedBaz.

Ten idiom językowy nie zadziała, jeśli postawisz klamrę w "złym miejscu" (które w innym języku programowania byłoby równie dobre i byłoby kwestią osobistych preferencji). Ot, kolejny z JavaScriptowych chochlików :).

Co do tego zagubionego średnika, który opisałeś na końcu posta, to też widywałem podobne rzeczy. Najczęściej nie przy ifie, tylko przy pętli for. Raz kumpel dobrą godzinę debugował taki błąd. Patrzył na kod i nie widział tego średnika. Pętla for to taki idiom, że człowiek automatycznie "wie", że nie może być błędu w tym prostym zapisie :D.

0

Pętla for to taki idiom, że człowiek automatycznie "wie", że nie może być błędu w tym prostym zapisie :D.

Zgadzam się i wtedy analiza nie pomaga, bo człowiek wie że tam błędu na pewno nie ma. Jedyne wyjście to debugowanie ew. instrukcja printf czy tam cout ;P.

Coraz bardziej nie lubię tego JS ;).
Twory typu:

getParent.removeChild 

zamiast remove etc.

Natomiast co do samego tematu, to mam prośbe o zobaczenie tej tabelki:
http://4programmers.net/Forum/659184?f=3#id659184

Zrobiłem chowanie w oparciu o colgroup i visibility: collapse, ale coś to tak nie śmiga jak powinno.
Na FF nie chowa prawidłowo, na IE 7 prawie dobrze. IE 8 w ogóle nie działa.
I tak kombinuje. Ta tabelka jest sporo większa, tylko teraz dla celów pokazania jej ją zmniejszyłem w szerokosci. Wolałbym jechać po kolumnach, niż po td-kach bo JS demonem szybkosci nie jest.

0

@tMbRaga:
To removeChild to akurat nie wina JavaScriptu. Taki po prostu jest standard DOM (Document Object Model), stworzony przez W3C. DOM jest zaimplementowany w różnych językach programowania, JavaScript to tylko jeden z nich. DOM jest niewygodny w użyciu; te długie nazwy mają sprawić, by nawet w nieobiektowych językach można było bez problemu uniknąć konfliktów nazw itd. Efekt jest taki, że w JS znacznie wygodniej skacze się po DOM choćby używając biblioteki jQuery.

Co do tamtej krowiastej tabelki, to przejrzałem, ale w kilka chwil nie ogarnąłem do końca o co chodzi, a na więcej nie mam teraz czasu/chęci.

1 użytkowników online, w tym zalogowanych: 0, gości: 1