Private Message form - friends list

as4s1n

New Member
Messages
174
Reaction score
4
Points
0
On my write message (PM) form I want the users to click on a link and a window would pop up with all their friends names' inside. I want them to click on a checkbox next to their name for all the friends they want to send it to and when they close it (via button on the bottom) the names are saved into the 'to' field. This is somewhat similar to the 'manage attachments' through this forum.

Please help, I am not quite sure how to do this.
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
A window created with window.open has a reference to the window that opened it via window.opener. Thus you can access form elements with window.opener.document.forms.formName.elements.elementName, as long as both windows are on a page in the same domain.

Alternatively, you can use a JS library widget (such as jQuery's UI/Dialog or a Prototype dialog) to create an in-page window. One big advantage to this approach is that you don't have to worry about popup blockers. Use AJAX to fetch the contents of the dialog.
 
Last edited:

as4s1n

New Member
Messages
174
Reaction score
4
Points
0
So, if I wanted to get all of the checked boxes I would do something like:

Code:
function returnFriends() {
// Page that used window.open input to field
var inputField = window.opener.document.forms.friendsList.elements.getElementById("name"),
// Checked boxes on this page
[COLOR=red]// objectsThatReturnCheckBoxesAsArray (please advise, assuming document.getElementsByTagName("inputs") but I do not know how to get only checked checkboxes)[/COLOR]
i =0,
checks;
for(i in check) {
     checks = check[i];
     inputField.value += checks.value;
     if(i < check.length)
            inputField.value += ", ";
}
}

I think that's what it should be.
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
You should indent blocks an additional level to make it more readable. That is,
Code:
function returnFriends() {
    // Page that used window.open input to field
    var inputField = ...
rather than
Code:
function returnFriends() {
// Page that used window.open input to field
var inputField = ...

Code:
function returnFriends() {
    // Page that used window.open input to field
    var inputField = window.opener.document.forms.friendsList.[COLOR="red"]elements.getElementById("name")[/COLOR],
The "elements" property is an HTMLCollection, not an Element, and thus doesn't have a getElementById method. If you want to use getElementById, call it on the form element (window.opener.document.forms.friendsList.getElementById(...)), or you can access the input by the name attribute with window.opener.document.forms.friendsList.elements.name (assuming the input is defined as <input name="name" ... />).

Code:
for(i in check) {
I wish we could do this, but this can be problematic as it will loop over all direct (i.e. non-inherited) properties, not just integer indices.

Code:
     if(i < check.length)
This test will always succeed, as i ranges from 0 through check.length-1.

// objectsThatReturnCheckBoxesAsArray (please advise, assuming document.getElementsByTagName("inputs") but I do not know how to get only checked checkboxes)
You could get all inputs and check whether they are checkboxes before processing them:
Code:
    var inputs = document.forms[0].elements,
        values = [];
    for (var i=0; i<inputs.length; ++i) {
        if (inputs[i].type == 'checkbox') {
            values.push(inputs[i].value);
        }
    }
    window.opener.document.forms.friendsList.elements.names=values.join(', ');

Or write a function that filters a collection of HTMLElements:
Code:
Array.prototype.map = function(fn) {
    var newSeq = [];
    for (var i=0; i < this.length; ++i) {
        newSeq[i] = fn(this[i]);
    }
    return newSeq;
}

Array.prototype.filter = function(keep) {
    var newSeq = [];
    for (var i=0; i < this.length; ++i) {
        if (keep(this[i])) {
            newSeq.push(this[i]);
    }   }
    return newSeq;
}

function map(seq, fn) {
    return Array.prototype.map.call(seq, fn);
}

function filter(seq, keep) {
    return Array.prototype.filter.call(seq, keep);
}

...

// returns true for checked checkboxes and radio buttons
function isChecked(elt) {
    return elt.checked;
}

function isCheckedCheckbox(elt) {
    return (elt.type == 'checkbox') && elt.checked;
}

...

function returnFriends(fromForm, toInput) {
    // if fromForm contains radio buttons, use isCheckedCheckbox
    var checks = filter(isChecked, fromForm.elements);
    toInput.value = checks.map(function(item){return item.value}).join(', ');
}
...
    returnFriends(document.forms[0], window.opener.forms.friendList.elements.friendList);

Or use jQuery:
Code:
function returnFriends(fromForm, toInput) {
    toInput.value=$.map(
        window.opener.$(':checkbox:checked'),
        function(item) { return item.value; }
    ).join(', ');
);

There are other alternatives, but they are mostly curiosities, so I won't mention them here.
 
Last edited:

as4s1n

New Member
Messages
174
Reaction score
4
Points
0
Cool, thanks. I had no idea about the window.opener. Say, do you know of a good JS tutorial, obviously I need to learn more.

Code:
    var inputs = document.forms[0].elements,
        values = [];
    for (var i=0; i<inputs.length; ++i) {
[color=red]        if (inputs[i].type == 'checkbox') {[/color]
            values.push(inputs[i].value);
        }
    }
    window.opener.document.forms.friendsList.elements.names=values.join(', ');
Your loop if() checks whether they are checkboxes, not whether they are checked or not so it returns every checkbox value. I changed it to
Code:
// ...
if(inputs[i].type == 'checkbox' && inputs[i].checked == true) {
//...

Code:
    var inputs = document.forms[0].elements,
        values = [];
    for (var i=0; i<inputs.length; ++i) {
        [COLOR=gree]if (inputs[i].type == 'checkbox')[COLOR=red] {[/COLOR]
            values.push(inputs[i].value);
        [COLOR=red]}[/COLOR][/COLOR]
    }
    window.opener.document.forms.friendsList.elements.names=values.join(', ');
@Misson: BTW, why do you include { }s when there is only one line? I do not waste the time (even though it is two characters) but it seems unnecessary.
 
Last edited:

essellar

Community Advocate
Community Support
Messages
3,295
Reaction score
227
Points
63
For JavaScript as a language, see Eloquent JavaScript. For the browser object model, you can look at W3Schools, but as a reference, Danny Goodman's "Dynamic HTML: The Definitive Guide (Second Edition)" is still unparalleled, even if it's getting a little old in the tooth.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Cool, thanks. I had no idea about the window.opener. Say, do you know of a good JS tutorial, obviously I need to learn more.
There were a few other resources mentioned in the "OO JS Issue" thread, including Eloquent Javascript. Also check out the Jibbering JS FAQs.

For specific topics in JS, read:

You should also read up on using JS debuggers, such as Firebug:
Safari and Chrome have their own debuggers; look them up. IE 8 now has a JS Debugger on par with Firebug.

Your loop if() checks whether they are checkboxes, not whether they are checked or not so it returns every checkbox value. I changed it to
As it says in the sig,
misson said:
Any posted code is intended as illustrative example, rather than a solution to your problem to be copied without alteration. Study it to learn how to write your own solution.

@Misson: BTW, why do you include { }s when there is only one line? I do not waste the time (even though it is two characters) but it seems unnecessary.
It's part of the coding style I follow. Leaving them out will cause bugs in rare instances where someone adds additional statements to the branch but neglects to add braces (which is rare, but does happen). Two characters take no time to type (if you use the right editor, they're inserted automatically, thus take no time to type) and don't increase the size of a file in any significant way. Bugs are more costly than the insignificant time and space costs.
 

as4s1n

New Member
Messages
174
Reaction score
4
Points
0
It's part of the coding style I follow. Leaving them out will cause bugs in rare instances where someone adds additional statements to the branch but neglects to add braces (which is rare, but does happen). Two characters take no time to type (if you use the right editor, they're inserted automatically, thus take no time to type) and don't increase the size of a file in any significant way. Bugs are more costly than the insignificant time and space costs.

Wouldn't that be their fault and have no connection to me if they make a typo, which would be easy to fix anyway? I use notepad XD so no editor to write it in for me.
 

essellar

Community Advocate
Community Support
Messages
3,295
Reaction score
227
Points
63
It would be their fault if the block were unambiguous -- and the best way to make a block unambiguous is to wrap it in the block syntax for the language you're using (curly braces, in the case of JavaScript and other languages that derive their syntax from Algol, parentheses in some others -- even indent conventions in languages that make end-of-block indicators easy to invisibly inline).

Habits, both good and bad, are easy to fall into and hard to break. Bad habits not only make one difficult to work with as a team member, they can also bite you in the posterior when you revisit your own code. There are some coding styles that can only be described as a matter of taste (for instance, I find banner-style indent to be the most readable and intuitive, but I'm up against a world of 1TBSers and must conform against my will), but there are things that are just plain best practices. Can your code be safely minified? Can a line be added without redefining control flow?
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Wouldn't that be their fault and have no connection to me if they make a typo, which would be easy to fix anyway?
While you could say it's their fault, the blame game isn't useful in development. If anything, it's counter productive.

Typos can be easily fixed, as can most simple bugs, but it still requires a little effort and extra time while you're testing the code (there's an extra test-and-fix cycle). Even worse, if someone commits the code without testing it (thinking "it's such a small change, it doesn't need to be tested"), they've just broken the source for everyone that checks it out. Better to never introduce the typo in the first place. Also, if you come across a line someone else added, it might not be immediately apparent whether the new line belongs in the block or not. If you alway place braces, it's a non-issue.
 

as4s1n

New Member
Messages
174
Reaction score
4
Points
0
That's a pretty good point, although, I don't really want to go back through all my code and change that. A good habit to form I suppose.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
I don't really want to go back through all my code and change that.
Exactly. Old code can be brought up to the current style if you happen to edit it for other reasons, but otherwise it's not an important enough task. Coding style is a matter for writing rather than maintenance.
 
Top