Animated loading indicators go a long way, but there are a few things to consider.
Expected wait time: Even a small delay needs to be dealt with or the user will be confused, frustrated, or try something else, but how to best deal with a one second delay is obviously very different from a process that's taking 5 seconds, 10 seconds, a minute, or hours. For a very brief delay of one or two seconds you want something subtle that doesn't take much processing on the user's part. A little animation on the control itself, and to indicate that nothing else should be done in the meantime you can change the cursor. For something that can take more than a couple of seconds you should provide more feedback: ideally already set the right expectations before the user even clicks, and tell the user what is happening and approximately how long it will take. Longer processes need different kinds of patterns to prevent the user from sitting and waiting in the first place, but I assume those are not what you are asking about.
Type of control: for some UI controls, users expect instant results, and disabling the control prevents the user from trying the same thing again, but it breaks common expectations. This includes checkboxes and any other controls that provide immediate visual feedback, such as radio buttons or dropdown lists. The user expects the state of these controls to change immediately, which is of course problematic if the value isn't known right away. That's simpler for a checkbox than a list because the next value can be anticipated, so what I like to do is change the control to the expected value (check the checkbox or radio button) and revert that change if the server comes back with something unexpected. Either way this adds to confusion, so it's best to stick to controls that don't need to visually change state, such as a button. Buttons are also good because they provide the label right on the control so you can give useful feedback there, such as a change of label and an animation right on the button.