Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.

Condiment posted:

I've found that modularizing has diminishing returns as the size and complexity of the app grows. You reach a point where you have to split your code up into separate files and directories in order to separate concerns and keep things sane.

To avoid having 15 separate HTTP calls in your app, there are build tools like Require.js that can concatenate all the files across your entire project into a single, minified file for production.

Yeah, I use Coffeescript, but this is sort of what I do. Difference is I use head.js and a Cakefile to manage building. When running development all the files are loaded in their separate files. When I build a deployment it concatenates all the files into a single.

That way you split concerns enough to make it easier to debug in the console, whilst keeping the HTTP calls down once you deploy. There's tools for that like CoffeeToaster, but I wanted to keep my structure and was already well into the project, so I just rolled my own solution.

In the end of the day client side applications are getting to the point where they compare in complexity to server applications, so your strategy will have to follow in step. Definitely make sure you're layering your services, modules, whatever in a way that doesn't tightly couple the whole lot, and organise your code to suit.

Adbot
ADBOT LOVES YOU

Tei
Feb 19, 2011

DreadCthulhu posted:

Any advice on how to best manage complexity for larger fat client JS apps? I'm mostly modularizing as much as I can at this point, anything else that works really well for you?

If you can build everything has "plugins" or "modules" that only leak 1 function to the world, the number of global anything will be very small.
You can have one JS file per module, and combine them, and send as a single http request, like Condiment say.

Have a piece of code that fake console.log for browsers that don't support it. So you can debug all your code with console.log and not have to comment them before production.

Storing data in the tags is risky, and not scale well when you have to store more data. Its generally better to store a object per item, even if you only need to store 1 integer, so if in the future the item need to store 2 integers, is easy to expand.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

DreadCthulhu posted:

Any advice on how to best manage complexity for larger fat client JS apps? I'm mostly modularizing as much as I can at this point, anything else that works really well for you?

In addition to what others have said, learn how to use closures to hide information and avoid polluting the global namespace. As you get used to closures you'll start seeing more and more ways to use them. I find in many ways they're more flexible than classes.

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope
Surround all your code with

JavaScript code:
(function () {
	"use strict";

	// your code here

}());
Or if you want to explicitly smuggle some global object into scope:

JavaScript code:
(function (globalObjectInScope) {
	"use strict";

	// your code here

}(globalObjectOutsideScope));

DreadCthulhu
Sep 17, 2008

What the fuck is up, Denny's?!
jQuery noob question: what is a sane and efficient way of creating a ton of elements in code and then appending them all at once to the DOM to avoid more than one redraw? For example, say I have an empty table with an id that I want to fill once some data is available to me. I imagine doing a separate .append() for each row (or column) would make for very lovely performance.

So far the best I could do was create an array of DOM elements, append to it, and then run a .append() at the very end. For example, assuming one single column for simplicity:

code:
var rows = dataArray.reduce(function(prev, value){

  var $row = $('<tr>');
  $row.append('<td>' + value.doMagic().toString() + '</td'>');

  // get the native element
  prev.push($row[0]);
  return prev;
}, []);

$('#my-table').append(rows);
Am I overcomplicating this? Supposedly working with pure strings instead of having jQuery parse the tag and create a DOM element + wrapper is 10x faster. Is that what pretty much everybody does?

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.
Would it possibly be worth investigating a template engine like HandlebarsJS? I don't really have experience with it but I'm assuming there's a point where building things bit by bit in jQuery is bad form for maintainability at the very least.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Use a DocumentFragment. Create a fragment, append everything to it, append the fragment to the document. Not sure how JQuery exposes that functionality.

In terms of general performance stuff, it's faster to use dom-based APIs (like document.createElement and appending a text value to it) instead of something that needs to parse HTML out of a string.

DreadCthulhu
Sep 17, 2008

What the fuck is up, Denny's?!

Maluco Marinero posted:

Would it possibly be worth investigating a template engine like HandlebarsJS? I don't really have experience with it but I'm assuming there's a point where building things bit by bit in jQuery is bad form for maintainability at the very least.

I'm using Underscore since it came for free with Backbone and I'm pretty happy with it. The whole idea, as far as I understand it, is to have a separate template for each Single Page App "page", so it comes quite handy there. Also really handy for individual components that are of predictable shapes, such as fixed size table rows or something like individual bars of bar charts. It's definitely great for modularity.

peepsalot
Apr 24, 2007

        PEEP THIS...
           BITCH!

DreadCthulhu posted:

jQuery noob question: what is a sane and efficient way of creating a ton of elements in code and then appending them all at once to the DOM to avoid more than one redraw? For example, say I have an empty table with an id that I want to fill once some data is available to me. I imagine doing a separate .append() for each row (or column) would make for very lovely performance.

So far the best I could do was create an array of DOM elements, append to it, and then run a .append() at the very end. For example, assuming one single column for simplicity:

code:
var rows = dataArray.reduce(function(prev, value){

  var $row = $('<tr>');
  $row.append('<td>' + value.doMagic().toString() + '</td>');

  // get the native element
  prev.push($row[0]);
  return prev;
}, []);

$('#my-table').append(rows);
Am I overcomplicating this? Supposedly working with pure strings instead of having jQuery parse the tag and create a DOM element + wrapper is 10x faster. Is that what pretty much everybody does?
If you want to build it with strings, and reduce calls to append then why not make one big string and call append once? Quickest way to concatentate a bunch of strings is pushing them onto an array and using Array.join
code:
var rows = dataArray.reduce(function(prev, value){
  prev.push('<tr><td>', value.doMagic().toString(), '</td></tr>');
  return prev;
}, []).join("");

$('#my-table').append(rows);
But yeah faster still would be to use DOM api directly: document.createElement, element.appendChild, etc.

peepsalot fucked around with this message at 03:59 on Feb 18, 2013

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Yes, please, introduce XSS vulnerabilities into your application. That sounds like an excellent idea.

DreadCthulhu
Sep 17, 2008

What the fuck is up, Denny's?!
I have no clue what that's referring to because I'm a filthy noob. Please explain.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
What happens if value.doMagic().toString() results in something that contains some HTML of its own?

This is another reason to prefer the DOM APIs - adding textual content is automatically safe, you don't need to escape things (and potentially forget about escaping it somewhere and introducing an XSS vulnerability).

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
I found this to be snappy in IE9 for inserting ~2000 rows, without calling the DOM directly or inserting unescaped text.

JavaScript code:
$('#my-table').append(
  $.map(dataArray, function(value)
  {
    var $row = $('<tr><td></td></tr>');
    $row.children().text(value.doMagic().toString());
    return $row;
  })
);
Or if you really want to crank it up this will go to 10,000 with a short delay, and it will finish for 50,000 if you give it time. (That's just constant strings, without accounting for doMagic):
JavaScript code:
$('#my-table').append(
  $.map(dataArray, function(value)
  {
    var row = document.createElement('tr');
    row.appendChild(document.createElement('td')).
      appendChild(document.createTextNode(value.doMagic().toString()));
    return row;
  })
);

Gazpacho fucked around with this message at 09:48 on Feb 18, 2013

Stoph
Mar 19, 2006

Give a hug - save a life.

Jabor posted:

What happens if value.doMagic().toString() results in something that contains some HTML of its own?

This is another reason to prefer the DOM APIs - adding textual content is automatically safe, you don't need to escape things (and potentially forget about escaping it somewhere and introducing an XSS vulnerability).

You can use a safe-by-default templating language like Handlebars. It even allows you to pre-compile and concatenate all of your templates into your minified JavaScript. It's working great for us at work in a Backbone.js application.

Elephantgun
Feb 13, 2010

Was unsure what thread to put this in so I'll throw it in here:



I'm currently doing an interactive art piece using primarily CSS3/HTML. The link is http://dawnhosie.com/staircase.html and is obviously in heavy prototype.

My biggest issue is that this is constructed by using multiple gifs placed on top of a much larger gif. If you cursor over the top-left section of the gif it will change. Yay/cool/wow/woah, but unfortunately they're .gifs so they get out of synch on page load. For the sake of the school project I can not use JS as the main backbone to the piece so that's not an option - it has to be CSS3/HTML5. What I can use it for, is for coding details.

I guess what I'm asking is is there any way to use Javascript to reset the .gif's to the beginning of their animation after the page is done loading without clearing the cache and having to have you redownload? At the moment they're coded as an opacity:0 in CSS which then transitions slowly to opacity:1 on roll-over. The page is already a massive enough download as it is (too massive, honestly) so clearing the cache really isn't an option. I just want the drat things to synch! I'm new to JavaScript so I'd have to be walked through it pretty hard, if it's even possible :blush:

The most reliable resource I could find was here, but I'm not quite sure I understand what they're talking about :

http://stackoverflow.com/questions/3191922/restart-an-animated-gif-from-javascript-without-reloading-the-image

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Does handlebars do contextual escaping? For example, if I do the following:

code:
<a href=/users/{{username}}>Visit {{username}} on Buttbook!</a>
Is that safe, or can I pwn everything by calling myself bob style=background-image:url(javascript:alert(1))?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Elephantgun posted:

Was unsure what thread to put this in so I'll throw it in here:



I'm currently doing an interactive art piece using primarily CSS3/HTML. The link is http://dawnhosie.com/staircase.html and is obviously in heavy prototype.

My biggest issue is that this is constructed by using multiple gifs placed on top of a much larger gif. If you cursor over the top-left section of the gif it will change. Yay/cool/wow/woah, but unfortunately they're .gifs so they get out of synch on page load. For the sake of the school project I can not use JS as the main backbone to the piece so that's not an option - it has to be CSS3/HTML5. What I can use it for, is for coding details.[/url]

Why can't you use just one gif for each animation?

Elephantgun
Feb 13, 2010

Jabor posted:

Why can't you use just one gif for each animation?

Because I code at 4 in the morning.

I feel silly now, easy solution right in front of my face.

Tei
Feb 19, 2011

My respect for most template engines is very low, since make the default action unsafe. The default action for writing a string in HTML should be converting to html entities. And the special use should be wen you want to output html (or any string really) unmodified.

In a HTML page*, on the internet**, the general rule*** is to avoid using Javascript to create content. So any javascript template engine is a flat out bad idea. Ideally**** content is created by a serverside template engine.

* ** *** **** on the real world, I see a few type of excepcions, like html applications that are already highly dependant on javascript, or pages that are strongly based on javascript to not suck (google maps, gmail)

Without any other rule, I would use "whatever comes with JQuery" as js template engine.
Noobs programmers using a js template engine sounds like asking for trouble...

Condiment
Oct 10, 2004
I WILL DESTROY THE OPPRESSIVE "TIPPING" SYSTEM BY BECOMING AN INSUFFERABLE TIGHTWAD

Tei posted:

Without any other rule, I would use "whatever comes with JQuery" as js template engine.
Noobs programmers using a js template engine sounds like asking for trouble...

Using jQuery as a JS template engine is inherently unsafe, since as others have discussed over the last several pages, jQuery does not automatically escape variables that are interpolated into a string for insertion into the DOM. The "noob programmer" must remember to explicitly escape their DOM output every single time.

On the other hand, I can't think of a single JS template library that doesn't automatically escape variables used in templates. Mustache and Handlebars both escape vars wrapped in {{ double braces }}, requiring {{{ triple braces }}} in order to write a context variable as unescaped HTML. Underscore uses <%= %> and <%- %> for unescaped and escaped strings, respectively.

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
What template engine that comes with jQuery are you referring to, anyway?

Generating HTML with Javascript is going to be routine in most any Ajax application. If Ajax requests return HTML fragments then they're not separating the model and view.

Gazpacho fucked around with this message at 01:08 on Feb 19, 2013

Gul Banana
Nov 28, 2003

what about applications which generated the HTML using server side templates in the first place, and are now supplying fragments generated by the same means?

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope
Yes yes, we get it, you can draw the line between model and view in several places, could we please not have this conversation. That only leads to a stupid debate about orthodoxy of the corner cases in any given architecture.

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Gul Banana posted:

what about applications which generated the HTML using server side templates in the first place, and are now supplying fragments generated by the same means?
They're brittle.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Hey I have an idea guys, let's make our AJAX endpoint completely unusable by anything except the current iteration of our web application by having it return HTML designed to be stuffed straight into our web application instead of just sending back the data. There is no way this is a bad idea.

Leavy
Feb 15, 2003

rufus

Jabor posted:

Hey I have an idea guys, let's make our AJAX endpoint completely unusable by anything except the current iteration of our web application by having it return HTML designed to be stuffed straight into our web application instead of just sending back the data. There is no way this is a bad idea.

If the original HTML of the page is rendered server-side, then why not use those same mechanisms to grab the same HTML via AJAX? I don't see the issue there. I'd even consider the alternative worse in that case, because if anything related to the markup changes, you would have two places to update it - in the js that is rendering the data, and the original server-side markup.

Now if your entire app is driven by generating markup through data it receives, then yeah, returning HTML on an AJAX call would be a Bad Idea. I think it really comes down to how your app has been built, and making generalizations like that isn't entirely accurate.

Gul Banana
Nov 28, 2003

Wheany posted:

Yes yes, we get it, you can draw the line between model and view in several places, could we please not have this conversation. That only leads to a stupid debate about orthodoxy of the corner cases in any given architecture.
i've got no intention of starting a debate; i was just curious, as a backend dev who is learning some web tech technologies at the moment.
honestly i'm hoping there IS a consensus/orthodoxy (this is doubtful)

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde

Gul Banana posted:

i've got no intention of starting a debate; i was just curious, as a backend dev who is learning some web tech technologies at the moment.
honestly i'm hoping there IS a consensus/orthodoxy (this is doubtful)
The problem is that people using the site during a template update would see glitches when they get new fragments sent to their old page. This could be avoided by maintaining the ability for clients to request any of several recent versions of the view, i.e. doing more work to compensate for bad architectural choices.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The obvious solution is to use a template system that can be rendered on both the client and the server, instead of being arbitrarily limited to one or the other.

Khorne
May 1, 2002
Are there any good resources for AngularJS? Specifically, is there a killer explanation of $scope and how it works? I feel like I am being a hack and throwing in the towel because I've resorted to using $rootScope for most of my broadcasts. I'm familiar with the documentation and a good number of the sample projects, and I've been hitting google pretty hard. It just seems like most of the example applications are excruciatingly simple and nothing at all like any of the sites I'd actually be developing.

I've ran in to a few mild annoyances. ng-class doesn't re-evaluate with angular's own hashbang routing, so your list sits there looking stupid if it's outside of ng-view. The easiest workaround for this is just to $scope.$on("$locationChangeSuccess") force a redraw of whatever element it is (in my case it's a list made with ng-repeat, so making angular think data has changed works fine). My first attempt at a solution was a custom directive, because I have a few lists that don't need a controller. They are completely static, but they link to various views of the application. The directive method works great for static lists, but if you try to use on a list generated by ng-repeat it's headache time.
code:
 <li ng-repeat="item in items" my-directive="active"><a href="#/view/{{item.id}}">{{item.name}}</a></li>
my-directive triggers and gives you $(element).children()[0].href = "#/view/{{item.id}}" instead of "#/view/0". This makes sense if you read the documentation, but it completely cock-blocks you in development. Custom directives activate before their child elements actually compile which seems like a bad decision. If there's a solution to this besides "put it after the repeated list and traverse up" which is just bad manners, I couldn't find it. I feel like it makes directives significantly less powerful for certain tasks, but there's a pretty good chance I am doing it wrong.

I'm liking it overall. I feel like I'm going to save time in the future by learning it now. It's definitely a successor to most of the currently popular frameworks.

It's crazy how nice developing in javascript is now. RequireJS, nodejs, almond, all of the unit testing and debugging tools available. You don't even need jQuery with angular, and jQuery itself was a really nice thing to me because I had to roll my own poo poo when IE5.5 was something worth supporting. My current project is actually 3 separate javascript projects. An angular frontend (only angular no require/jquery/etc), a standalone library that is only using requirejs so far because it handles dependencies and building, and a nodejs backend. The library has an interface that angular interacts with and abstracts away whether it is being ran client or server side, and the library's interface can easily be used in nodejs to run server side. Getting the library completely integrated with angular was shockingly trivial. I've had more trouble drawing lists than doing that.

edit: The reason I chose javascript for something that can get slightly computationally expensive is that it can be ran client side, and the type of application I am building is usually distributed as a binary rather than a webapp. The added benefit of being able to offer a scalable mobile version of the site for a premium with very little extra development time is ridiculously awesome. I've also always loved javascript. Even when most people said "Don't use javascript ever!"

Khorne fucked around with this message at 01:04 on Feb 20, 2013

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.
I'd love to hear this too. I built this prototype but I have a few thoughts to how I can do things better next time around. In a complicated application you definitely need to make more use of custom directives to make things more performant, I think, as some of the built in ways to handle hiding and what not can be very slow indeed. Leave a lot of cruft in the DOM to slow things down.

Bodhi Tea
Oct 2, 2006

seconds are secular, moments are mine, self is illusion, music's divine.
Say that I want to bind events to elements that I know only exist on certain pages. What's the best practise in this case to avoid having to include different js files on each page? Would I simply check if the element exists on the page before I do anything?

how!!
Nov 19, 2011

by angerbot

Bodhi Tea posted:

Say that I want to bind events to elements that I know only exist on certain pages. What's the best practise in this case to avoid having to include different js files on each page? Would I simply check if the element exists on the page before I do anything?

Use selectors that are unique across pages. Or put a unique class on the body tag and select all elements like this: $("body.mypage #element")

Stoph
Mar 19, 2006

Give a hug - save a life.

Bodhi Tea posted:

Say that I want to bind events to elements that I know only exist on certain pages. What's the best practise in this case to avoid having to include different js files on each page? Would I simply check if the element exists on the page before I do anything?

Yes, I use this pattern sometimes:

code:
// Option 1
function option1() {
    var $videoContainer;

    $videoContainer = $('.video-widget');

    // No need to check if element exists because the jQuery plugin will handle
    // it for us (empty result set means the plugin call does not do anything)

    $videoContainer.yourPlugin();
}

// Option 2
function option2() {
    var $videoContainer;

    $videoContainer = $('.video-widget');

    // Check if our element exists because we might want to have some
    // custom logic that only runs if the element(s) exist(s)
    if (!$videoContainer.length)
        return;

    // Use custom crap
    // There is potential bug here because $videoContainer.data is
    // using the data from the first element in the jQuery result set - there
    // might be multiple elements in the $videoContainer result set
    $videoContainer.yourPlugin(customCrap($videoContainer.data('yourDataAttrs')));
}

// Option 3 (most elegant to me)
function option3() {
    var $videoContainer;

    $videoContainer = $('.video-widget');

    // Don't need a check for element existance because we are using $.each
    // anyway and it won't run if no elements match

    $videoContainer.each(function () {
        var $container = $(this);
        $container.yourPlugin(customCrap($container.data('yourDataAttrs')));
    });
}
There are a lot of variations on this kind of pattern and you just pick one that makes poo poo work correctly.

Stoph fucked around with this message at 23:41 on Feb 24, 2013

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.
I'm certain that this will be a very stupid question, but I'm having trouble with a very simple thing.

On this page: http://pastebin.com/AK0tNarW, can anyone tell me why the function initUserTypes (ln 67) doesn't run when the radio button "yes" (ln 121) is clicked?

Help much appreciated... :)

Blinkz0rz
May 27, 2001

MY CONTEMPT FOR MY OWN EMPLOYEES IS ONLY MATCHED BY MY LOVE FOR TOM BRADY'S SWEATY MAGA BALLS

Newf posted:

I'm certain that this will be a very stupid question, but I'm having trouble with a very simple thing.

On this page: http://pastebin.com/AK0tNarW, can anyone tell me why the function initUserTypes (ln 67) doesn't run when the radio button "yes" (ln 121) is clicked?

Help much appreciated... :)

You're missing assignment operators on lines 76 and 92. Those lines should read:
code:
var initUserTypes = function()
code:
var submit = function()

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.
I loving hate javascript.

ON THAT NOTE:

Can I plug something into eclipse that will give me some red Xs whenever I try to do this stuff?

e: thanks a lot :)

smug forum asshole
Jan 15, 2005
jshint?

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?
Also shouldn't the browser's console warn you about that when you load the page?

You are using the browser's debug tools, right?

Adbot
ADBOT LOVES YOU

Stoph
Mar 19, 2006

Give a hug - save a life.
I use a great plugin for Sublime Text 2 for JSHint called SublimeLinter. You can install it very easily with the Sublime Text 2 Package Control plugin. It also lints (shows syntax errors) in PHP.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply