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
Pollyanna
Mar 5, 2005

Milk's on them.


What experience have you guys had with Knockout.js? Is it like a replacement for Angular or something, or is it totally different from that?

Adbot
ADBOT LOVES YOU

Pollyanna
Mar 5, 2005

Milk's on them.


Hummm. I think I brought this up before in the web dev thread, but I was looking to recreate this in HTML/tables format, and figured that a JS framework would work best for it. Would Angular or Knockout be better for this?

Pollyanna
Mar 5, 2005

Milk's on them.


A MIRACLE posted:

Knockout isn't a framework, it's a library that binds the resulting html to the current state of your application. So if you want to write a program in javascript, and not worry about manually rendering stuff to the screen, use knockout.

:psyduck: Whoops I got that wrong then. What I was thinking of was some sort of tool that's basically a text field, then a list of text fields with an associated integer, then a table of variable rows, then a radio button or something. Would it make sense to try and MVC that or is that better done through plain HTML?

Pollyanna
Mar 5, 2005

Milk's on them.


Well, okay. Here's the implementation I was thinking of: There's a text field with the "upsetting event", then a list of smaller text fields with associated 0-100 numbers, then a table with three column and variable rows, and I'm imagining a button that lets you add more rows as you need them. Then there's a radio button 'do you feel better' prompt and then you can like hit submit or something to record your log to a database/JSON thingy.

That's why I wanted some sorta framework. Does that explain the reasoning a bit better? I looked at Knockout cause the tutorials were all about form submission and dynamic tables 'n poo poo so I thought it was a good place to start.

Pollyanna
Mar 5, 2005

Milk's on them.


Sagacity posted:

I have to second the love for Knockout. I've been using ever since it got first released, wrote the mapping plugin (sadly not too much time to maintain it nowadays) and have been happily using it ever since. For some reason it was never considered to be as 'sexy' as Angular or Ember, but it's really well thought-out and really fast. Certainly the performance tuning has some caveats (i.e. it's still faster to render a huge grid just by concatenating strings instead of doing it using nested templates) but it's amazing for what it is.

But what I especially like about it, is that it works on any reasonably recent browser. This includes IE7 and 8. Those browsers suck terribly, but it's much better than what Angular is doing. Especially the whole Angular 2.0 thing where they're going 1) mobile-first and 2) dropping support for anything below IE11.

I liked Knockout, but I never managed to get every data-bound input field in my old app to correctly change into text on unfocus. :saddowns: It either didn't work or made getting data a huge pain.

...Incidentally, I'm thinking about another approach. Is it possible to disable the input box "border" on an unfocused input box, such that it looks like the input is text before you click on it, or is there a better way to do what I'm describing?

Pollyanna
Mar 5, 2005

Milk's on them.


That's what I tried to do in Knockout, but it wouldn't work for more than one input. I tried adding flags to the VM data to keep its focused/unfocused state, but that made storing and retrieving the data a huge pain in the rear end.

Pollyanna
Mar 5, 2005

Milk's on them.


We should put that in the title.

I'm amazed at all the different choices for MV* frameworks on Javascript. What the hell do I choose :gonk: we're interested in teaching our clients Ember for our upcoming class, but I dunno if I like it - too opinionated. I personally like more freeform/simple and obvious frameworks like Knockout and React (although I dunno if React is actually MV* instead of just V). I'm thinking my next project will be a for-real single page app with no reloading, RESTful CRUD, and cutesy little UX widgets so I can get right into a good MVC framework. Problem is which one to choose :v: so I'm starting with just reviewing how JS implements MVC/MVVM in general. That's what made Python/Ruby frameworks make sense to me, after all. Maybe we should also cover a little bit of how MVC works in here, too.

Pollyanna
Mar 5, 2005

Milk's on them.


So in Ember, why is it that we define things like:

code:
App.ThingRoute = Ember.Route.extend({
    model: function() {
        return thing;
    }
});
instead of like:

code:
App.ThingRoute = Ember.Route.extend({
    model: thing
});
where thing is assumed to just be a generic object? What's the point of passing in a function instead of just a reference to that object?

Pollyanna
Mar 5, 2005

Milk's on them.


I'm having trouble structuring an Ember application in Middleman. I have my directories set up like this:

code:
javascripts
    job-app-tracker
        templates
            app.emblem
        _routes.em
        _models.em
        _controllers.em
        _views.em
        app.js
    all.js
where all.js looks like this:

code:
//= require 'jquery'
//= require 'underscore'
//= require 'backbone'
//= require 'handlebars'
//= require 'ember'
//= require 'ember-data'
app.js looks like this:

code:
//= require_tree .

// Initialize your app here.

$(function() {
	App = Ember.Application.create({});
});
and controllers.em (EmberScript) looks like this:

code:
# Define your controllers here.

$ ->
	class AppController extends Ember.Controller
	App.AppController = new AppController
I can't help but think there's a better way of doing this. What's the typical directory for a medium-sized Ember application? Am I doing this correctly? And why doesn't my template show up on the page?

code:
# application.emblem

h1 Hello World
I also run into the issue where instantiating App.AppController happens before App is defined as the Ember application.

Pollyanna fucked around with this message at 18:19 on Aug 20, 2014

Pollyanna
Mar 5, 2005

Milk's on them.


^^ Ooh, I like! I've considered using React for generating views 'n all, but I'm not sure how it'd interact with Ember. Maybe I should work on Backbone again for a while...

Kobayashi posted:

^ I don't know what Middleman is, but that doesn't look like any Ember app I've ever seen. I normally wouldn't chime in since this is not really my area of expertise, but Ember is really opinionated about how things get done (which is why I like it). If you're not going to do things "the Ember way," then you're going to run into poo poo like this at every turn. Right now, "the Ember way" seems be Ember CLI. As it stands, it looks like you're using a combination of standard Javascript (app.js), Coffeescript? (controllers.em), and whatever Emblem is. Any one of those could be breaking Ember's "convention over configuration" assumptions.

Anyway, to answer your question, the Ember CLI documentation expects outlines where it expects to see things. Personally, I prefer pod structure. The Ember core team has indicated that pod structure is the future, but the tooling isn't as good yet.

On an unrelated note, HTMLbars just landed in canary, so soon the world will be freed from the scourge of metamorph tags! :neckbeard:

.em is EmberScript, a CoffeeScript dialect that has first-class support for Ember objects, extensions, etc. It helps make it clear exactly what I'm doing and keeps me in the Ember "mindset". app.js is because I wanted to use Sprockets to include everything under the job-app-tracker scripts directory. Emblem is a templating library.

I've used Ember CLI, but I'm not sure if it's meant to be used in conjunction with Middleman. The whole thing about Middleman is that it's basically "drop your stuff here, reference it when you need it", and the Ember CLI generates a whole bunch of crap like Bower packaging and also apparently it uses import foobar which I have never seen used like that outside of Python so I'm like what. It confuses the hell out of me, since it seems to expect me to use the tools it supplies for developing and deploying the application, which is not what I'm doing. If all it did was generate the directories and placeholder controllers.js/models.js and all, I'd be happy. Maybe I'll see if it can do that.

I'm absolutely not doing it by convention at all simply by trying to work Ember into Middleman's structuring. There's no official support for Ember like there is with Rails, so I kinda have to work from the ground up. I'm tempted to port my site to Rails, though, cause of how much of a pain it is :(

Pollyanna
Mar 5, 2005

Milk's on them.


I'd love to learn a bit more about how front-end MVC frameworks work, but I have trouble learning the basics in a Javascript context. Is there some sort of MVC framework that uses similar concepts (like two-way binding, events, controllers, etc.) in a language like Ruby or Python? I'm just mentally allergic to Javascript.

Pollyanna
Mar 5, 2005

Milk's on them.


Front-end, maybe. But I still don't quite get what all this poo poo does in a Backbone application, or why I need all of it:

JavaScript code:
/*global Backbone, jQuery, _, ENTER_KEY */
var app = app || {};

(function ($) {
	'use strict';

	// The Application
	// ---------------

	// Our overall **AppView** is the top-level piece of UI.
	app.AppView = Backbone.View.extend({

		// Instead of generating a new element, bind to the existing skeleton of
		// the App already present in the HTML.
		el: '#todoapp',

		// Our template for the line of statistics at the bottom of the app.
		statsTemplate: _.template($('#stats-template').html()),

		// Delegated events for creating new items, and clearing completed ones.
		events: {
			'keypress #new-todo': 'createOnEnter',
			'click #clear-completed': 'clearCompleted',
			'click #toggle-all': 'toggleAllComplete'
		},

		// At initialization we bind to the relevant events on the `Todos`
		// collection, when items are added or changed. Kick things off by
		// loading any preexisting todos that might be saved in *localStorage*.
		initialize: function () {
			this.allCheckbox = this.$('#toggle-all')[0];
			this.$input = this.$('#new-todo');
			this.$footer = this.$('#footer');
			this.$main = this.$('#main');
			this.$list = $('#todo-list');

			this.listenTo(app.todos, 'add', this.addOne);
			this.listenTo(app.todos, 'reset', this.addAll);
			this.listenTo(app.todos, 'change:completed', this.filterOne);
			this.listenTo(app.todos, 'filter', this.filterAll);
			this.listenTo(app.todos, 'all', this.render);

			// Suppresses 'add' events with {reset: true} and prevents the app view
			// from being re-rendered for every model. Only renders when the 'reset'
			// event is triggered at the end of the fetch.
			app.todos.fetch({reset: true});
		},

		// Re-rendering the App just means refreshing the statistics -- the rest
		// of the app doesn't change.
		render: function () {
			var completed = app.todos.completed().length;
			var remaining = app.todos.remaining().length;

			if (app.todos.length) {
				this.$main.show();
				this.$footer.show();

				this.$footer.html(this.statsTemplate({
					completed: completed,
					remaining: remaining
				}));

				this.$('#filters li a')
					.removeClass('selected')
					.filter('[href="#/' + (app.TodoFilter || '') + '"]')
					.addClass('selected');
			} else {
				this.$main.hide();
				this.$footer.hide();
			}

			this.allCheckbox.checked = !remaining;
		},

		// Add a single todo item to the list by creating a view for it, and
		// appending its element to the `<ul>`.
		addOne: function (todo) {
			var view = new app.TodoView({ model: todo });
			this.$list.append(view.render().el);
		},

		// Add all items in the **Todos** collection at once.
		addAll: function () {
			this.$list.html('');
			app.todos.each(this.addOne, this);
		},

		filterOne: function (todo) {
			todo.trigger('visible');
		},

		filterAll: function () {
			app.todos.each(this.filterOne, this);
		},

		// Generate the attributes for a new Todo item.
		newAttributes: function () {
			return {
				title: this.$input.val().trim(),
				order: app.todos.nextOrder(),
				completed: false
			};
		},

		// If you hit return in the main input field, create new **Todo** model,
		// persisting it to *localStorage*.
		createOnEnter: function (e) {
			if (e.which === ENTER_KEY && this.$input.val().trim()) {
				app.todos.create(this.newAttributes());
				this.$input.val('');
			}
		},

		// Clear all completed todo items, destroying their models.
		clearCompleted: function () {
			_.invoke(app.todos.completed(), 'destroy');
			return false;
		},

		toggleAllComplete: function () {
			var completed = this.allCheckbox.checked;

			app.todos.each(function (todo) {
				todo.save({
					completed: completed
				});
			});
		}
	});
})(jQuery);

Pollyanna
Mar 5, 2005

Milk's on them.


I think my question is more on understanding and implementing a more general model-view-controller setup. Like, make a simple one from scratch in Ruby or Python to understand why the gently caress we'd want to do it and what the important bits are. I know that frameworks differ, but there has to be some sort of commonality, right?

Pollyanna
Mar 5, 2005

Milk's on them.


I want to move on to doing T/BDD in Javascript. Is this book recommended, or there a better reference out there?

Pollyanna
Mar 5, 2005

Milk's on them.


Yeoman doesn't seem to be able to locate my generators. I ran yo and selected generator-front-end-basic, which responded with this:

code:
[?] Here's what I found. Install one? generator-front-end-basic
generator-front-end-basic@0.1.0 /Users/rebecca/npm/lib/node_modules/generator-front-end-basic
&#9492;&#9472;&#9472; yeoman-generator@0.14.2 (stuff)


I just installed your generator by running:

    npm install -g generator-front-end-basic
...but it doesn't actually seem to be installed.

code:
Rebeccas-MacBook-Pro-2:flux rebecca$ yo front-end-basic
Error front-end-basic 

You don't seem to have a generator with the name front-end-basic installed.
You can see available generators with npm search yeoman-generator and then install them with npm install [name].
To see the 0 registered generators run yo with the `--help` option.
After some fuckery with figuring out where everything is installed, I discovered that it works just fine if I run it in /Users/rebecca/npm/lib/node_modules:

code:
Rebeccas-MacBook-Pro-2:flux rebecca$ cd /Users/rebecca/npm/lib/node_modules
Rebeccas-MacBook-Pro-2:node_modules rebecca$ yo front-end-basic

     _-----_
    |       |
    |--(o)--|   .--------------------------.
   `---------´  |    Welcome to Yeoman,    |
    ( _´U`_ )   |   ladies and gentlemen!  |
    /___A___\   '__________________________'
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

[?] Author Name: (myself <myself@foo.com>) 
What's going on here? Is this a directories issue or is something else the problem?

Pollyanna
Mar 5, 2005

Milk's on them.


HaB posted:

I am completely spitballing, here, but usually when you do any sort of npm install -g you need to sudo it, or it will permission error all over the place.

If you see any red text when installing - do it again, via sudo

Doesn't quite explain (i zoned out and didnt finish this part of the post. ignore me)

i noticed that my npm is running from /usr/local/bin/npm, but npm config get prefix was set to /Users/rebecca/npm. I changed it to /usr/local/lib/node_modules/npm. Now the Backbone generator is getting installed to /usr/local/lib/node_modules/npm/lib/node_modules/generator-backbone... and I have a feeling that means it's the wrong directory :gonk:

What directories am I expected to have for Yeoman?

edit: I ultimately removed everything npm/node related from my computer and reinstalled using Homebrew. Everything works now!

Pollyanna fucked around with this message at 20:22 on Nov 6, 2014

Pollyanna
Mar 5, 2005

Milk's on them.


I have a question about React, Backbone, and creating reusable modules for use with NPM, Gulp, and Browserify.

I'm making a webapp that uses React for its views, and I'm also planning to use Backbone to keep track of models and collections. Right now, I have everything in one bigass app/jsx/ folder where all my scripts live. I'm wondering how I would make an NPM module out of my React views, and my Backbone setup.

Right now, I'm importing my top-level React app like this:

code:
var MyApp = require('./app.jsx');
when I want to do something a little nicer, like this:

code:
var MyApp = require('my-app');
How would I package up a folder structure that looks something like this, so I can reuse it if I decide to redo my project?

├── app.jsx
├── authScreen
│   ├── common
│   │   ├── authButton.jsx
│   │   ├── emailInput.jsx
│   │   ├── passwordConfirmation.jsx
│   │   └── passwordInput.jsx
│   ├── loginScreen.jsx
│   └── signupScreen.jsx
├── main.jsx
├── searchForm
│   ├── cuisineSelection.jsx
│   ├── locationInput.jsx
│   ├── searchButton.jsx
│   └── searchForm.jsx
├── searchResults
│   ├── cuisineChoice.jsx
│   ├── restaurantListing
│   │   ├── restaurantCard
│   │   │   ├── cardInformation.jsx
│   │   │   ├── profileImage.jsx
│   │   │   └── restaurantCard.jsx
│   │   └── restaurantListing.jsx
│   └── searchResults.jsx
└── title.jsx

Pollyanna
Mar 5, 2005

Milk's on them.


Aha, that's done it. Thanks :3:

I've figured out something with React: if you want to do make an AJAX-driven webapp type thing, don't pass in mutable data as properties - meaning, don't pass in a big ol' god object with a "user" and "meals" and "results" attributes. Instead, pass in only what you know will never change - in this case, the API URLs! Build all the data objects from JSON within getInitialState and componentDidMount, since those data objects will change over time.

Pollyanna fucked around with this message at 16:13 on Dec 8, 2014

Pollyanna
Mar 5, 2005

Milk's on them.


I'm still wrapping my head around Flux. The Dispatcher pattern is a very new concept to me and the way data stores work requires an adjustment when coming from the Models of MVC. As for it not being recommended, it may be that way - this is just what works best for (and makes the most sense to) me.

There's another thing about React that I'm thinking about. I currently have a form declared something like this (WIP):

code:
var CommentForm = React.createClass({
  getInitialState: function() {
    return {
      title: '',
      text: ''
    };
  },
  render: function() {
    return (
      <form class='comment-form'>
        <CommentTitleInput />
        <CommentTextInput />
        <CommentSubmitButton />
      </form>
    );
  }
});

var CommentTitleInput = Render.createClass({
  getInitialState: function() {
    return {
      title: ''
    };
  },
  render: function() {
    return (
      <div class='comment-title-input'>
        <label>Comment Title</label>
        <input placeholder="My Title"></input>
      </div>
    );
  }
});

var CommentTextInput = Render.createClass({
  getInitialState: function() {
    return {
      text: ''
    };
  },
  render: function() {
    return (
      <div class='comment-text-input'>
        <label>Comment Text</label>
        <input placeholder="My Text"></input>
      </div>
    );
  }
});

var CommentSubmitButton = Render.createClass({
  render: function() {
    return (
      <button>Add Comment</button>
    );
  }
});
Currently, the CommentForm holds a title state and a text state. The CommentTitleInput also holds a title state, and the CommentTextInput also holds a text state. I have a feeling this is incorrect - this seems to go against the "single source of truth" principle that the React docs talk about a lot.

Intuitively, I'd say that the CommentTitleInput keeps the title state and the CommentTextInput keeps the text state - but then it becomes difficult to actually submit the form, because neither of CommentForm's child components naturally have access to all the data that must be submitted. Meaning, I'd have to somehow make a function in CommentSubmitButton that "grabs" the data from CommentTitleInput and CommentTextInput and then posts the data to the server. Not only is that apparently discouraged in the React documents, I can't actually fuckin' do that, at least not in a way that isn't a huge pain in the rear end.

So the real solution is to keep the title and text state in the CommentForm component, and also create an onFormSubmit method to pass into CommentSubmitButton that will be called when the button is clicked and will submit the form - and also have access to the form's state, which holds the data that must be submitted!

It helps to think of it as an electronic appliance. The CommentForm has three wires going out to three outer pieces of electronics - one goes to the "input title" keyboard, another goes to the "input text" keyboard, and another goes to the "submit form" pushbutton. When using it, you type on the keyboards and then press the button. What's actually happening is that the outer components themselves don't do poo poo - they're just IO outlets that send data to the CommentForm black box.

What I'm wondering is how I'm supposed to "predict" where all this state should live. Why does the CommentForm keep the state, as opposed to its parent component(s)? Why shouldn't I just keep a global state in the topmost component that looks something like this?

code:
getInitialState: function() {
  return {
    blogPost: {
      article: {
        title: '',
        text: ''
      },
      commentsBox: {
        comments: [
          {
            title: '',
            text: ''
          }
        ],
        commentForm: {
          title: '',
          text: ''
        }
      }
    }
  };
}
You'd just pass in each bit of state to the matching components - e.g. blogPost.article to Article, blogPost.commentsBox to CommentsBox (parent of CommentForm), etc. I can't think of a reason NOT to do this, aside from there being a lot of passing around happening - but I feel that's a minor price to pay for ensuring a single source of truth for all state.

I know I'm kind of thinking of this in an odd way kinda, I've been trying to tackle a complicated SPA using React (how the gently caress do I dynamically change which component is rendered/currently exists :() and I've ran into enough pitfalls and confusion that I'm going back to the basics again. But I think I have a better handle on it now than I used to.

Pollyanna
Mar 5, 2005

Milk's on them.


One problem that Flux has is that it exposes too much of the internal wiring, it feels like. Being expected to build an EventEmitter for every Store I make feels like busy work and like something that could be automagically abstracted away for me. I've got a reading list of React stuff to go through, so I'll try and see if there's a better explanation of it somewhere.

Pollyanna
Mar 5, 2005

Milk's on them.


Maybe there's a singular top-level controller that splits off into smaller component controllers. Or something. Then technically there's a single source of data, it's just divided up.

Pollyanna
Mar 5, 2005

Milk's on them.


I'm wondering how I "add" and "remove" components in React. I've got a Search Form and a Search Results component, and I always want to display the Search Form, but only render the Search Results when the search button's clicked. Would it basically look something like this?

code:
  handleSubmit: function(event) {
    event.preventDefault();
    var results = searchPlaces(params);
    React.render(<SearchResults results={results}>, this.props.resultsEl);

Pollyanna
Mar 5, 2005

Milk's on them.


Lumpy posted:

I second Thermopyle's recommendation to look at React. For fun, learn Ampersand (https://ampersandjs.com) as well. It's a different take on Backbone, and looks pretty interesting.

Thirding this! Ampersand is a really neat framework, and I'm gonna move onto it next once I'm satisfied putzing around with React. I really think that front-end developers have to be familiar with a bunch of different frameworks, because the state of technology in the field changes fast and you have to adapt to survive.

I think wraithgar works on Ampersand, if they're around...

Pollyanna
Mar 5, 2005

Milk's on them.


shodanjr_gr posted:

What do you mean? The only garbage that I've found is the relatively verbose boilerplate for setting up new directives...overall it absolutely blows my mind how much angular accomplishes with just a few lines of code...

...that you see. For basic stuff and CRUD, it's pretty simple, but if you want anything more complicated than that, then you have to create your own directives, which means you then have to read up on how Angular expects you to program modules and organize your project, and then that means you've touched the surface of the documentation and you figure "hey this can't be that bad" and no it is that bad it is really that bad.

Backbone might take more typing overall, but I found that I actually knew what the gently caress was going on when I used it. Unlike in Angular. Also, gently caress compiling :shepicide:

glompix posted:

With a NoSQL database like Mongo the idea is that your JSON document is your datarow and your primary key is a GUID.

This...is a lot less horrible than I thought. I expected Mongo to be some complicated monstrosity, not just what's basically a GUID version of a Javascript array. I might have to look into this.

Pollyanna
Mar 5, 2005

Milk's on them.


bartkusa posted:

I don't work with Google Maps, but I would be surprised if Google didn't let you pass in a DOM node, instead of an HTML string.

From what I've used of Google Maps, it expects DOM nodes, rather than HTML strings.

edit: Ooh, wait, this is for InfoWindow. I haven't tackled those yet (but soon!), so I don't know how it treats them.

Pollyanna fucked around with this message at 19:44 on Jan 12, 2015

Pollyanna
Mar 5, 2005

Milk's on them.


I've actually have a bit of trouble reconciling React and Backbone/Ampersand/M-whatever. As I understand it, with React applications, you pass in data and receive rendered HTML:

JavaScript code:
var pollyanna = {
    name: "Pollyanna",
    age: 24
};

var Hello = React.createClass({
    render: function() {
        return (
            <div>
                <h1>
                    Hello, {this.person.name}!
                    You are currently {this.person.age} years old.
                </h1>
            </div>
        );
    }
});

React.render(<Hello person={pollyanna}/>, document.body);
If I were to, say, create a button that changed my name to uppercase when I clicked it, I would make a method like this:

JavaScript code:
    handleButtonClick: function() {
        var newName = "POLLYANNA";
        this.person.name = newName;
        // or, with a framework like Backbone:
        this.person.set('name', newName);
    },
However, this is apparently discouraged, since the React component has to know implementation details about the data storage/Model in order to modify it. So, React expects there to be some sort of event distribution system or somesuch in order for it to work properly. Which means you have to do something like this:

JavaScript code:
    handleButtonClick: function() {
        var newName = "POLLYANNA";
        EventDispatcher.trigger('nameChange', newName);
    }
where you now have to add at least one new method to your Model:

JavaScript code:
    registerCallback: function() {
        EventDispatcher.register(this.handleNameChange, 'nameChange');
    },
    handleNameChange: function(name) {
        this.set('name', name);
    },
The problem I see with this is that React really isn't a drop-in solution for a View layer at all. Using React means you have to restructure your application to use event dispatching, which if you're making something in Backbone or Ampersand is handled directly by the View and is therefore a core functionality of the framework. That's not easily changed. Not to mention that you still have to manually update your React component using forceUpdate() when your Model or Collection has changed - if React really is just "pass in data, get HTML out", how come it doesn't update itself when that data changes? It's bizarre.

Pollyanna
Mar 5, 2005

Milk's on them.


Anyone here use gulp? I'm trying to think of a way to make using it a little easier for me to handle.

As I understand it, gulp makes use of streams and piping to build/concatenate and watch files. The basic idea is that a source file is input, several transforms are placed upon it, and a finalized source file is output. For example, if I wanted to take a file app/main.js, run Browserify on it, Uglify it, then output it as bundle.js to a dist/src directory, it'd look something like this (adapted from here):

JavaScript code:
var browserify = require('browserify');
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');

gulp.task('browserify', function() {
  return browserify('./app/main.js')
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(buffer())
    .pipe(uglify()) 
    .pipe(gulp.dest('./dist/src'));
});
This is kind of an ugly way to pipe the results of a function into another. To me, it's easier to understand like this:

code:

# |> is piping, -> is a method called on the previous argument after piping (fuckin' bundle())

(((('./app/main.js'
  |> browserify -> bundle), 'bundle.js')
  |> source
  |> buffer
  |> uglify), './dist/src')
  |> gulp-dest
In plain English, I:

  • pipe my source file into browserify, returning the result
  • call bundle() on the result of the previous operation, returning the result
  • pipe the result of the previous operation, along with the new file's filename, into source, returning the result
  • pipe the result of the previous operation into buffer, returning the result
  • pipe the result of the previous operation into uglify, returning the result
  • pipe the result of the previous operation, along with our dist/src directory, into dest.

This way, it's clear to see that it's a procedure with a set of transformations performed on a given input. If we conceptualize what gulp does as a series of transforms given certain inputs, with no regard to an overarching global state, then it's easy to think of it in a functional manner. All I ever really need to pass in are three pieces of data: my source file's location, the name of my output file, and the directory that new file will be in. So, I could break up that larger piping into pieces:

code:
: browserify-bundle (source-file)
  # we assume that each function returns something (puts it onto the "stack", maybe?)
  source-file
    |> browserify -> bundle

: bundle-source-to-buffer (source-file, new-file)
  (source-file
    |> browserify-bundle, new-file)
    |> source
    |> buffer

: uglify-bundle-buffer (source-file, new-file)
  (source-file, new-file)
    |> bundle-source-to-buffer
    |> uglify

: write-bundle-to-dest (source-file, new-file, file-destination)
  (source-file, new-file)
    |> uglify-bundle-buffer, file-destination)
    |> gulp-dest

# now we create our new task
(('./app/main.js', 'bundle.js', './dist/src')
  |> write-bundle-to-dest, "browserify")
  |> gulp-task
You could also do like I mentioned and take a stack based approach, since we're assuming that every function returns something - functions just act on n pieces of the stack at any time, and you add to the stack to add other inputs to a function. source-file new-file file-destination write-bundle-to-dest "browserify" gulp-task, or something.

Does this make sense? Personally this way is easier for me to express exactly what I want to happen when I make a gulp task: I just want to push something into a black box, and have something else come out the other end. I was hoping that an approach like this would work well, but it looks like stuff like bundle and streams throw a wrench into this plan...I think. I still have to think about how to actually implement something that takes advantage of this, too.

yes i did just start learning about functional programming and stack based languages, why do you ask

Pollyanna
Mar 5, 2005

Milk's on them.


What employer and coworkers? I'm not even employed quite yet. And besides, I'm not actually going to implement this, it's just a thought experiment (unless somebody does want me to make it in which case I was completely serious).

Pollyanna
Mar 5, 2005

Milk's on them.


Oh man, I am super pumped for React Native. That looks so goddamn cool.

Pollyanna
Mar 5, 2005

Milk's on them.


Suspicious Dish posted:

We got an Angular site shipped from some external contractor. I've been trying to hack on it to add simple functionality and it's the most insane thing I've ever done.

Angular is an incomprehensible mess and I can't figure out how to do anything in it.

Finally, you and I agree on something. I'm working on a beast of an Angular project and it makes me weep.

Pollyanna
Mar 5, 2005

Milk's on them.


Speaking of yeoman generators, what's the most accepted way to start up a new React SPA project? This would be something that only interacts with an API, so it won't require a back-end like Express or anything. Something that just compiles to static HTML/ES6/CSS and that I can just publish onto a lovely intranet Windows server or something (it's complicated).

Pollyanna
Mar 5, 2005

Milk's on them.


What's the point at which you should start using a framework? Our big ol' dynamic HTML table/Excel spreadsheet replacement/inline form editing Frankenstein has an issue with hiding/resetting forms via a cancel button and after fiddling around with jQuery spaghetti and completely disorganized, inline source code, I'm frustrated enough to want to convert the whole thing to a React component instead of Rails form helpers and wash my hands of the whole thing. Front-end poo poo has been a recurring issue for us and absolutely none of it makes sense. :gonk: The lack of a framework is making things just totally stupid.

Pollyanna
Mar 5, 2005

Milk's on them.


Suspicious Dish posted:

try refactoring it before rewriting it to the latest hotness

This is how I'm refactoring it. It's a use case that clearly doesn't map well to the technology used to make it (Rails forms), and faking SPA-like behavior by using XHR requests to load up HTML and recording state in the markup is only making this harder to debug and understand, and it's slowing us down. The app needs to move on from throwaway jQuery callbacks and slapdash element styling if we want to go further with it, or it's just going to get worse.

Opulent Ceremony posted:

I maintain several pages like this at work. How large and complex is your page currently? If it isn't terrible and if your team already has a preferred framework being used elsewhere in the application, it could be a great idea to convert it. The pages I mentioned have no hope of conversion: they are enormous, very complex, have no tests, and maintain such a tremendous list of undocumented specific functionality that even if I wanted to rewrite the whole thing, I wouldn't even be able to tell if it did everything it was supposed to and would be bombarded constantly with critical hotfix requests as a result of the heavy client use they see. Don't let it become like the pages I inherited.

It's not particularly large, but it's disorganized enough that the complexity is way higher than it should be. We have no real framework in our application aside from some jQuery scattered about. There's a team writing regression tests (Capybara stuff) right now, so maybe once those are finished I'll bring up the idea of fixing our front-end to not be insane.

Pollyanna
Mar 5, 2005

Milk's on them.


Spraynard Kruger posted:

React just rolled out a configuration-less app creator: https://facebook.github.io/react/blog/2016/07/22/create-apps-with-no-configuration.html

Spins up a Webpack/Babel/ESLint setup for you, no configuration files mixed in with your code or mountains of dependencies in your package.json necessary. Very cool stuff.

Also important to note that there's an "eject" function that pushes all the internal configuration into your project repo and detaches you completely from the conventions. Makes going rogue a lot easier. I'm totally using this next time I do a React thing :3:

Pollyanna
Mar 5, 2005

Milk's on them.


Thermopyle posted:

What stage Babel transpilation does it do?

The problem with removing configuration is that...there are things people commonly want to configure!

Yes, and there's an option to bail and just shunt the default config into your project, which you can then customize.

Pollyanna
Mar 5, 2005

Milk's on them.


Thermopyle posted:

"Yes" what?

:confused: Just kind of how I started the sentence.

Pollyanna
Mar 5, 2005

Milk's on them.


Ohhh, I see. That was a response to your second sentence, it should be customizable once you eject.

Pollyanna
Mar 5, 2005

Milk's on them.


Dependency hell might suck but it's better than unorganized jQuery callbacks randomly peppered throughout server side templates.

Pollyanna
Mar 5, 2005

Milk's on them.


I'm on a new project using React where we're tasked with building a drop-in component that's basically a form that takes some parameters, has a button to get results, and renders them in a nice looking little graph. I'm inheriting some code for a ticket that implements the code to populate the results from an HTTP call. This branch pulls in react-redux and adds a bunch of Redux-specific code and components, and it's much less simple and straightforward now where our prior approach worked just as well and is easier to develop in. I feel like incorporating react-redux just makes the project more complex for no real advantage or improvement over what we do, and I don't really understand why it's being brought in and integrated. How do I question the reasoning behind using react-redux to people on a project I've newly joined without coming off as pushy or overly questioning?

I guess the main question is, what do I do if I disagree with a proposed approach? I could say "I don't think this is worth it", but I worry that I'd be stepping out of line with that.

Pollyanna fucked around with this message at 21:07 on Dec 7, 2016

Adbot
ADBOT LOVES YOU

Pollyanna
Mar 5, 2005

Milk's on them.


Yeah, that's why I didn't want to say anything. It's more likely than not that I have no idea what's going on, so gently caress it, whatever floats their boat.

With that said, I'm wondering how to redirect to another route as part of a reducer/action. Upon hitting a button, we send an action with data from an API and update the store with it. However, Redux is functional and I don't know where something with side effects like Router is used. Is there a particular way to do this in Redux?

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