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
ATM Machine
Aug 20, 2007

I paid $5 for this

pram posted:

I'm messing around with AngularJS. I like it a lot so far, but I'm having a hard time figuring out how to make some pagination links. I haven't been able to find any good examples on stackoverflow etc :shepface:

My json schema already has pagination, it includes these items:

code:
    "per_page": 5,
    "pages": 36,
    "current_page": 1,
So I can get the total number of pages and the last page from "pages" and the current page obviously. I thought about doing an ng-repeat but it doesn't seem like you can just iterate over things that aren't actually in the scope. It this a job for a filter, or something else?

You'd want something outlined here. Basically its a job for a custom function that you call in the ng-repeat, but you give it pages as its input, then bind the function that creates an array of n-length to the scope.

Adbot
ADBOT LOVES YOU

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

Raskolnikov2089 posted:

I wrote a simple form input that does some calculations. Since I'm not writing to a database, do I need to sanitize my inputs?

Basically the page takes in two integers, divides them and returns the value.

You still might want to do that, because non-numeric strings converted to numbers become NaN in Javascript and that will ruin your calculation. Also if you display the input values to the user, there is a possibility of an injection attack.

pram
Jun 10, 2001

ATM Machine posted:

You'd want something outlined here. Basically its a job for a custom function that you call in the ng-repeat, but you give it pages as its input, then bind the function that creates an array of n-length to the scope.

Welp I ended up putting this in the controller for the time being, after wasting an hour trying to write a directive.

code:
        $scope.totalPages = data.thread.pages;
        $scope.pages = [];

       for ( var i = 1; i <= $scope.totalPages; i++ ) {
          $scope.pages.push( i );
        }

ATM Machine
Aug 20, 2007

I paid $5 for this

pram posted:

Welp I ended up putting this in the controller for the time being, after wasting an hour trying to write a directive.

code:
        $scope.totalPages = data.thread.pages;
        $scope.pages = [];

       for ( var i = 1; i <= $scope.totalPages; i++ ) {
          $scope.pages.push( i );
        }

No need for a directive if you aren't doing much more than showing a list of page numbers: Scratch that.

code:

$scope.totalPages = data.thread.pages;
$scope.generatePageArray = function(num) {
    return new Array(num);
}

The above should do the trick, just call ng-repeat="i in generatePageArray(totalPages) track by $index" on the dom element you want to repeat, and {{$index+1}} within that element to display the number. totalPages will reference the $scope variable, and likewise for generatePageArray.

The following might work as a directive:

code:
app.directive('pagination',
  function() {

    var linkFunction = function(scope, element, attributes) {
	  scope.pages = attributes["pages"];
	  scope.currentPage = attributes["currPage"];
    };

    return {

      restrict: 'E',
      templateUrl: '../partials/fragments/pagination.html',
      link: linkFunction,
      controller : function(scope) {

        $scope.generatePageArray = function() {
          return new Array(scope.pages);
        }

      } //End controller

    } //End return directive

  } //End function
);
To use this, place it in its own file called directives.js, or wherever, and make sure the templateUrl lines up with where you store the file, then create the element where you want to use it with <pagination pages="{{pages}}" currPage="{{current_page}}">, with the curly braced variables relating to your $scope variables in your controller.

The template file will contain the actual markup for the pagination, so a ul > li or a repeating div what have you, with ng-repeat="i in generatePageArray() track by $index" in the element you want to repeat.

I'm hoping thats alright, its been awhile since I've touched angular. A few things that got me is that the directive name is what you refer to it by in the markup, and restrict defines how it'll be represented, E standing for element, so <pagination> for this.

camelCased directives need to be dash-seperated within the markup, otherwise angular won't do anything and probably bitch at you.

The link function is called before the replacement iirc, so this can be used to set scope (not $scope) variables local only to this directive, though you can use $scope as well, this can lead to conflicts with the controllers $scope.

Some or all of this could be or probably is wrong, but hopefully it gets you a little bit on the right track.

ATM Machine fucked around with this message at 14:29 on Jun 29, 2014

Goon
Apr 22, 2006
what is with the parenthesis syntax for object patterns?

var objPattern = ( function () { //... })();

I don't understand why there's the parenthesis enclosing the function and a second set of empty parenthesis.

Chenghiz
Feb 14, 2007

WHITE WHALE
HOLY GRAIL

Goon posted:

what is with the parenthesis syntax for object patterns?

var objPattern = ( function () { //... })();

I don't understand why there's the parenthesis enclosing the function and a second set of empty parenthesis.

That's an immediately invoked function expression: http://benalman.com/news/2010/11/immediately-invoked-function-expression/

And now looking this up to make sure I was right has taught me something too!

EVGA Longoria
Dec 25, 2005

Let's go exploring!

Goon posted:

what is with the parenthesis syntax for object patterns?

var objPattern = ( function () { //... })();

I don't understand why there's the parenthesis enclosing the function and a second set of empty parenthesis.

Javascript has a very limited concept of Scope. To work around that, you create an anonymous function:

JavaScript code:
(function() {
...
})
That will get a nice, clean scope to build from, and don't pollute the global name space with anything.

You can then immediately invoke it after you define it, with the () at the end:

JavaScript code:
(function() {
...
})();
That executes what you had in there.

You write a function like this to return your goal (be it a function, an object, an array, or even a string), and then you put this after a var definition:

JavaScript code:
var cleanObj = (function() {

return {};

})();
and cleanObj will be defined as {}.

pram
Jun 10, 2001

ATM Machine posted:


To use this, place it in its own file called directives.js, or wherever, and make sure the templateUrl lines up with where you store the file, then create the element where you want to use it with <pagination pages="{{pages}}" currPage="{{current_page}}">, with the curly braced variables relating to your $scope variables in your controller.

The template file will contain the actual markup for the pagination, so a ul > li or a repeating div what have you, with ng-repeat="i in generatePageArray() track by $index" in the element you want to repeat.

I'm hoping thats alright, its been awhile since I've touched angular. A few things that got me is that the directive name is what you refer to it by in the markup, and restrict defines how it'll be represented, E standing for element, so <pagination> for this.

camelCased directives need to be dash-seperated within the markup, otherwise angular won't do anything and probably bitch at you.

The link function is called before the replacement iirc, so this can be used to set scope (not $scope) variables local only to this directive, though you can use $scope as well, this can lead to conflicts with the controllers $scope.

Some or all of this could be or probably is wrong, but hopefully it gets you a little bit on the right track.

Nice, thanks! I haven't seen anyone pass in attributes like this before (but I haven't really looked at much angular code tbh)

Goon
Apr 22, 2006

EVGA Longoria posted:

Javascript has a very limited concept of Scope. To work around that, you create an anonymous function:

JavaScript code:
(function() {
...
})
That will get a nice, clean scope to build from, and don't pollute the global name space with anything.

You can then immediately invoke it after you define it, with the () at the end:

JavaScript code:
(function() {
...
})();
That executes what you had in there.

You write a function like this to return your goal (be it a function, an object, an array, or even a string), and then you put this after a var definition:

JavaScript code:
var cleanObj = (function() {

return {};

})();
and cleanObj will be defined as {}.

Thanks! That makes sense

ATM Machine
Aug 20, 2007

I paid $5 for this

pram posted:

Nice, thanks! I haven't seen anyone pass in attributes like this before (but I haven't really looked at much angular code tbh)

You can normally just access scope values from the controller in directives, but for some reason I keep thinking I ran into problems with that, and just did it this way until I figured it out, then promptly forgot. Angular is kind of tricky, then you have an ah-hah! moment, and suddenly it just makes sense.

Howmuch
Apr 29, 2008
I've mainly worked on back-end c# code and I'm still clumsy with javascript.
I've got a multiselect box with filters that say which "blocks" to show and which ones to hide.

It's working fine when there's just one filter but when there's more it only shows blocks according to one of the filters.

Any ideas or suggestions on how to implement this?
code:
var blocks = document.getElementsByClassName("scheduleItem");
code:
function filterTable() {
            var filters = $("#filters option:selected").map(function () {
                return $(this).val();
            }).get();

            console.log("current filters: " + filters);

            for (var i = 0; i < blocks.length; i++) {
                if (filters.length == 0) {
                    if (endsWith(blocks[i].className, "hide")) {
                        $(blocks[i]).removeClass("hide");
                    }
                }

                for (var j = 0; j < filters.length; j++) {

                    if (blocks[i].className.indexOf(filters[j]) > -1) {

                        if ($(blocks[i]).hasClass("hide")) {

                            $(blocks[i]).removeClass("hide");
                        }
                    }
                    else {
                        if (!endsWith(blocks[i].className, "hide")) {
                            $(blocks[i]).addClass("hide");
                        }
                    }
                }
            }
        }

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Do you know what the flaw in your code is? Try stepping through it and observing the results, especially the last iteration of the j loop. The other question I had was why do you use hasClass in one place but manually inspect the className everywhere else. Also why you bother checking if the class already exists (or doesn't exist) before adding and removing it, since the APIs you're using are specified as just being a no-op if you try and add a class that already exists, or remove one that isn't present.

Anyway, what you want to do is show the current block if it matches any of your filters, and hide it if it matches none of them. There a bunch of ways to do this depending on how masturbatory you want to get with jQuery and stuff.

Howmuch
Apr 29, 2008

Jabor posted:

Do you know what the flaw in your code is? Try stepping through it and observing the results, especially the last iteration of the j loop.

Ouch, yeah. It makes sense now.


Jabor posted:

The other question I had was why do you use hasClass in one place but manually inspect the className everywhere else. Also why you bother checking if the class already exists (or doesn't exist) before adding and removing it, since the APIs you're using are specified as just being a no-op if you try and add a class that already exists, or remove one that isn't present.

I didn't even know addclass, removeclass or hasclass existed until today. :)
I'm still getting my feet wet with javascript so the code will look like crap for now.

What is the best way to debug javascript, by the way?
Are breakpoints an option somewhere?

Chenghiz
Feb 14, 2007

WHITE WHALE
HOLY GRAIL

Howmuch posted:

Ouch, yeah. It makes sense now.

I didn't even know addclass, removeclass or hasclass existed until today. :)
I'm still getting my feet wet with javascript so the code will look like crap for now.

What is the best way to debug javascript, by the way?
Are breakpoints an option somewhere?

The devtools in chrome are your best friend: https://developer.chrome.com/devtools/docs/javascript-debugging

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Browsers have pretty decent debugging tools nowadays - just go to wherever you're looking at your console output, find the tab that shows you the JS source, and then double-click to set a breakpoint just like any IDE debugger.

Howmuch
Apr 29, 2008

Jabor posted:

Browsers have pretty decent debugging tools nowadays - just go to wherever you're looking at your console output, find the tab that shows you the JS source, and then double-click to set a breakpoint just like any IDE debugger.
Awesome, thanks!

lunar detritus
May 6, 2009


Are there any tutorials for using breakpoints? Theoretically I understand them and I have used them a couple of times but it still feels like I'm doing it wrong.

lunar detritus fucked around with this message at 15:51 on Jun 30, 2014

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

gmq posted:

Are there any tutorials for using breakpoints? Theoretically I understand them and I have used them a couple of times but it still feels like I'm doing it wrong.

There isn't a lot to them, really.

"What the hell is the value of x when you get to this statement" (just breakpoints, watches and using the console to evaluate things)
"How did we get here and what was the value of y in the calling function" (stack trace)
"What the hell is the value of x when you get to this statement and z > 3" (conditional breakpoints)

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer
I'm trying to write a firefox extension but I don't see a thread for that. I know Java and M but my Javascript is weak.

I'm trying to get a button to appear only if the url starts with a certain string:
JavaScript code:
require("sdk/tabs").on("ready", isSA);

function isSA(tab) {
	var url = tab.url;
	var saregex='http://forums.somethingawful.com/showthread.php';
	if (saregex.test(url)) modSA(tab,url);
	}
	
function modSA(tab, url){
	var buttons = require('sdk/ui/button/action');
	var tabs = require("sdk/tabs");
	var button = buttons.ActionButton({
		id: "boner-button",
		label: "Maintain your Erection",
		icon: "./icon.png",
		onclick: handleClick
		});
	}
function handleClick(state) {
	var panel = require("sdk/panel").Panel({
	width: 180,
	height: 180,
	contentURL: require("sdk/self").data.url("boners.html")
	});
	panel.show();
}
My guess is that you simply can't create buttons inside a function like this, but what's the alternative? Google hasn't been helpful. Do button objects have a Visible modifier?

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

LeftistMuslimObama posted:

I'm trying to write a firefox extension but I don't see a thread for that. I know Java and M but my Javascript is weak.

I'm trying to get a button to appear only if the url starts with a certain string:
JavaScript code:
require("sdk/tabs").on("ready", isSA);

function isSA(tab) {
	var url = tab.url;
	var saregex='http://forums.somethingawful.com/showthread.php';
	if (saregex.test(url)) modSA(tab,url);
	}
	
function modSA(tab, url){
	var buttons = require('sdk/ui/button/action');
	var tabs = require("sdk/tabs");
	var button = buttons.ActionButton({
		id: "boner-button",
		label: "Maintain your Erection",
		icon: "./icon.png",
		onclick: handleClick
		});
	}
function handleClick(state) {
	var panel = require("sdk/panel").Panel({
	width: 180,
	height: 180,
	contentURL: require("sdk/self").data.url("boners.html")
	});
	panel.show();
}
My guess is that you simply can't create buttons inside a function like this, but what's the alternative? Google hasn't been helpful. Do button objects have a Visible modifier?

I don't know anything about Firefox extension programming, but it looks like you're not adding the button to the ui anywhere. You just create a button. Maybe that's how Firefox extensions work, I don't know.

The MUMPSorceress
Jan 6, 2012


^SHTPSTS

Gary’s Answer

Wheany posted:

I don't know anything about Firefox extension programming, but it looks like you're not adding the button to the ui anywhere. You just create a button. Maybe that's how Firefox extensions work, I don't know.

What I've got there is their sample code for adding a button to the UI, just part of it moved into the function. Mozilla's documentation is not great, but I'll have to keep digging in there to figure this out I guess.

edit: Figured it out in case anyone cares. You do, in fact, add buttons to Firefox just by declaring the variables, but you can only do it at the beginning of your script. There's no way to do it conditionally, the constructor for the button has to be called when the extension starts, basically. This isn't stated anywhere in their documentation, but that's the behavior I'm seeing.

The MUMPSorceress fucked around with this message at 20:56 on Jul 1, 2014

Raskolnikov2089
Nov 3, 2006

Schizzy to the matic
**nevermind

VVV I figured out why I was confused immediately after posting, but your jsfiddle makes it even more clear. Thank you.

Raskolnikov2089 fucked around with this message at 23:12 on Jul 1, 2014

fletcher
Jun 27, 2003

ken park is my favorite movie

Cybernetic Crumb
'a' is the index of the array (i.e. data[0], data[1], etc)

'b' is the object at that array index

Check out this fiddle for an example: http://jsfiddle.net/EuSms/1/

piratepilates
Mar 28, 2004

So I will learn to live with it. Because I can live with it. I can live with it.



Is there a nice way of having a module in Javascript (particularly Node) optionally take an object to instantiate it?

Like say I have a file called 'myFile.js' and I do

code:
var myFile = require('./myFile.js);
But I'd also like to optionally be able to pass in options like so

code:
var myFile = require('./myFile.js')( {} );
is there a way of writing myFile.js that won't require me to do this if I don't want to pass in any options:

code:
var myFile = require('./myFile.js')();

Strong Sauce
Jul 2, 2003

You know I am not really your father.





You cannot do something like that exactly...

The closest is to extend the functionality as a property of the function object you use.

JavaScript code:

var fn = function(opts);

fn.OtherUse = {
  fn1: function() {},
  fn2: function() {},
  fn3: function() {}
}

module.exports = fn
Then
JavaScript code:
var s = require('./myfile.js')({})

var t = require('./myfile.js').OtherUse

excidium
Oct 24, 2004

Tambahawk Soars
Need some ideas on how the best way to tackle this issue. I'm using an API call to get back all of the data on a page. The data is returned in an array of objects containing properties about the field including the name, value, caption, format, data type, read only, required and show condition. Now all of this would be easy to just spit out on the page in the order it appears in the API response but I would like to introduce a way to "design" a page layout. I'm using AngularJS so the idea is to create a template view for each page type that lays out the data and then uses the response to populate all of the values/attributes that make up the page.

code:
"controls": [
    {
      "name": "AccountInput.Name",
      "value": "",
      "reference": "aB046627977D44D39A44C680C395B6522",
      "caption": "First Name,
      "dataType": "string",
      "controlType": "text",
      "format": "",
      "maxLength": "50",
      "readOnly": "0",
      "hidden": "0",
      "required": "0"
    },
    {
      "name": "AccountInput.Address1",
      "value": "",
      "reference": "aB046627977D44D39A44C680C395B6522",
      "caption": "Address 1",
      "dataType": "string",
      "controlType": "text",
      "format": "",
      "maxLength": "30",
      "readOnly": "0",
      "hidden": "0",
      "required": "0"
    },
    ...
]
How can I do this since all of the individual objects are in an array (meaning I can't just easily path down to them through object notation)?

pram
Jun 10, 2001
You can use the orderBy filter on ng-repeat, theres a pretty good example in the docs (surprisingly)

https://docs.angularjs.org/api/ng/filter/orderBy

excidium
Oct 24, 2004

Tambahawk Soars

pram posted:

You can use the orderBy filter on ng-repeat, theres a pretty good example in the docs (surprisingly)

https://docs.angularjs.org/api/ng/filter/orderBy

Not sure how that will help though - ideally I would be able to use the same logic on all pages rather than having to know the list of all possible fields and ordering them. This also introduces a problem if a field just isn't in the response as the order would then be messed up. Still stumped!

pram
Jun 10, 2001
Oh, so.. you just want to use the json data in your view, right?

You can use $resource or $http to query the json, and then put that data into your controller scope.

For example

code:
app.service('Stuff', ['$resource',
    function ($resource) {
        return $resource('/api/whatever', { }, {
            get: {
                method: 'GET'
            }
        });
    }
]);

app.controller('getStuff', ['$scope', 'Stuff',
    function ($scope, Stuff) {

        $scope.data = Stuff.get();

    }
]);
Then in your route template you'd use something like:

code:
<div ng-repeat="control in data">
<span ng-bind="control.name"></span>
</div>

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
Why wouldn't the field be in the response? That seems like a weird thing to happen in the first place. Your only option is to normalize the data when it comes into your app by looping over it and filling in the blanks with something acceptable (null?), but that will affect the sort order. If you need to use placeholders specific to the field type, you're best having the API return something for the field.

With the arbitrary ordering, whatever makes up your series of field headers should also include the fieldname with the header element as a value. Then the ng-click callback can reference that value.

Pseudocode ahoy
code:
<tr>
    <th ng-repeat="field in fields">
        <a href="" ng-click="changeSort(field)">{{field}}</a>
    </th>
</tr>
<tr ng-repeat="row in table | orderBy:orderBy:orderDirection">
    <td ng-repeat="col in row">{{col}}</td>
</tr>

$scope.orderDirection = 1;
$scope.changeSort = function(field) {
    if ($scope.orderBy == field) {
       $scope.orderDirection = !$scope.orderDirection;
    }
    $scope.orderBy = field;
};
Apologies if the code is complete crap, I haven't done angular in ages.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?
Is short circuiting of && and || something you can rely on? As in, do all major browsers do it?

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope

HappyHippo posted:

Is short circuiting of && and || something you can rely on? As in, do all major browsers do it?

Yes

neurotech
Apr 22, 2004

Deep in my dreams and I still hear her callin'
If you're alone, I'll come home.

I have a node.js application that makes use of passport and passport-google to handle Google authentication. As part of the login/authentication process, Passport serializes and deserializes the logged in user's information (name, email, etc) and passes said information into my jade templates via express as locals.

I have an Angular form that POSTs it's contents with $http.post to my API (which is also handled by the same application).

How can I inject the aforementioned user information locals into the payload that is sent by $http.post?

Here's my code for reference: https://github.com/neurotech/observations/tree/google-auth

Excuse the bad code. This is a huge learning project for me!

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.
Are you looking to have the user details attached to each request, so you're not using something like cookies to persist authentication with each request? Take a ganders at this SessionInjector example which intercepts http requests and appends session details onto the end.

Give the injector an extra function to set the user details and use $httpProvider.interceptors.get('yourServiceName') to fetch the service and set the user.. or have the interceptor use another service to store/fetch the user details.

Take a look at this nifty auth service I just stumbled across, which gives you a nice interceptor that can defer requests if they fail due to not being logged in, firing an event, which gives you the opportunity to login the user and then have the interceptor resend the requests.

neurotech
Apr 22, 2004

Deep in my dreams and I still hear her callin'
If you're alone, I'll come home.


Thanks for getting back to me so quickly. I managed to get things working in a roundabout way.

My next problem is to do with leveldb - does anyone know if there's a way to query a leveldb instance based on what the values are, rather than the keys?

In SQL terms:
code:
SELECT * FROM observations WHERE observations.author = 'x'

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

neurotech posted:

Thanks for getting back to me so quickly. I managed to get things working in a roundabout way.

My next problem is to do with leveldb - does anyone know if there's a way to query a leveldb instance based on what the values are, rather than the keys?

In SQL terms:
code:
SELECT * FROM observations WHERE observations.author = 'x'

It sounds like your problem would be a better fit for an actual relational database, rather than a key/value store.

neurotech
Apr 22, 2004

Deep in my dreams and I still hear her callin'
If you're alone, I'll come home.

Jabor posted:

It sounds like your problem would be a better fit for an actual relational database, rather than a key/value store.

Possibly. I really like the speed and API of LevelDB in node, so I think I'm going to stick with it and add author information to my keys.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

Please help me find my stupid Fabric.js error. I'm trying to center things in a group, which AFAICT is the default behaviour, and it's not happening.

I took this code from the Groups tutorial section, and it doesn't work with master or 1.4.0 -- the text is anchored at the top-left:

code:
var text = new fabric.Text('hello world', {
  fontSize: 30
});

var circle = new fabric.Circle({
  radius: 100,
  fill: '#eef',
});

var group = new fabric.Group([ circle, text ], {
  left: 150,
  top: 100,
  angle: -10
});

canvas.add(group);
See also http://jsfiddle.net/xGtvj/

From reading the code, I actually don't see anywhere that it even tries to center things; Group.prototype._updateObjectCoords just offsets the object by the group's top-left location.

v1nce
Sep 19, 2004

Plant your brassicas in may and cover them in mulch.

neurotech posted:

Possibly. I really like the speed and API of LevelDB in node, so I think I'm going to stick with it and add author information to my keys.

What are you making? Does the underpants-burning speed provided by LevelDB justify the annoying to work with "database" you're about to build?

Adbot
ADBOT LOVES YOU

Chenghiz
Feb 14, 2007

WHITE WHALE
HOLY GRAIL

Jabor posted:

It sounds like your problem would be a better fit for an actual relational database, rather than a key/value store.

Why is it that every new hot database seems to be key/value? Are relational databases like postgresql and mssql just that perfected/done?

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