HTML is not updated when using Mootools dragging - html

I'm using Mootools (don't think it is related to the problem) to drag and drop and element.
var draggable = new Drag(timeHandle, {
onDrag: function () {
var calculatedTime = calcTime();
$('timeLabel').innerHTML = calculatedTime;
},
});
Basically, I can drag my 'timeHandle' and the 'timeLabel' is getting updated properly.
The problem is that sometimes, after moving the handle a little bit, suddently, the UI is not getting updated. The 'timeHandle' is not moving and the 'timeLabel' is not getting updted.
The problem is not with the drag event, I can see it keeps on getting called.
When I move
$('timeLabel').innerHTML = calculatedTime;
everything works fine.
So, the problem is not with the 'Drag' object since the event is kept on calling.
Looks like some UI performance issue.
Thanks

To simplify your code, you can use Element.set('text', 'my text here');
var element = $('timeLabel');
var draggable = new Drag(timeHandle, {
onDrag: function () {
element.set('text', calcTime());
}
});
Also, remember to remove that last comma or it will throw errors in Internet Explorer.

OK, found a to make it work.
I still not sure what caused the problem but it looks like the 'innerHTML' command has either really poor performance which causes problems in the GUI updates or maybe some kind of internal mechanism (IE only? which is supposed to prevent the UI from updates overflow.
Anyway, instead of using the innerHTML, I'm doing the following:
var draggable = new Drag(timeHandle, {
onDrag: function () {
var calculatedTime = calcTime();
var element = $('timeLabel');
element.removeChild(element.firstChild);l
element.appendChild(element.ownerDocument.createTextNode(calculatedTime));
},
});
Works like a charm

Related

How do I format my AngularJS data model?

Hi I am just beginning with angular and I am struggling to find the answer to what I'm sure is quite a simple thing to do.
I am currently getting the values of some input boxes and pushing them into my scope. This is creating one long 'array' eg:
['data-1','data-2','data-3']
I would like to format my data in the following way instead
$scope.data = [
{
'header1': 'data1-1',
'header1': 'data1-2',
'header1': 'data1-3'
},
{
'header1': 'data2-1',
'header1': 'data2-2',
'header1': 'data2-3'
}
]
This is my function as it currently is.
$scope.createRow = function(){
angular.forEach(angular.element("input"), function(value, key){
$scope.td.push($(value).val());
});
}
Any help or pointers would be greatly appreciated as I am just getting my head round the angular way
Doing this isn't hard... but before I give you a gun to shoot yourself in the foot, just to say that I think it would be beneficial to explain WHY you want structure in that other format you are mentioning. You seem to have lots of data repetition and that's always a red flag.
Now for the code, you just need to create object before pushing it to the array like:
$scope.createRow = function(){
angular.forEach(angular.element("input"), function(value, key){
var obj = {
"header1": val + "-1",
"header2": val + "-2"
};
$scope.td.push(obj);
});
}
EDIT:
OK, so you are trying to add new row to the table. First of all, you shouldn't be doing angular.forEach, but rather those input elements in HTML should bind to existing scope object, like:
// obviously use better names than Input1Value
// I am here just giving you example
$scope.bindData = {
Input1Value: null,
Input2Value: null
};
// in HTML you will do
// <input ng-model="bindData.Input1Value" />
// <input ng-model="bindData.Input2Value" />
Now that you've eliminated that nasty angular.forEach you need to have some kind of event handler, for example when user clicks the button you want to add this object to the array to which table is data bound. Just be sure to clone the $scope.bindData object when you add it to array.
$scope.createRow = function(){
var newRowData = $scope.cloneObject($scope.bindData);
$scope.td.push(newRowData);
}
// http://heyjavascript.com/4-creative-ways-to-clone-objects/
// https://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object
$scope.cloneObject = function(objToClone) {
var newObj = (JSON.parse(JSON.stringify(objToClone)));
}
To close this answer off - keep in mind, if you ever find yourself directly referencing HTML DOM elements in Javascript with AngularJS - you are doing something wrong. It's a nasty habit to eliminate, especially if you are coming from jQuery background (and how doesn't?), where everything is $("#OhHiThere_ElementWithThisId).
Obviously the main thread on this topic on StackOverflow is this one:
“Thinking in AngularJS” if I have a jQuery background?
However I find that it's too theoretical, so Google around and you may find better overviews like:
jQuery vs. AngularJS: A Comparison and Migration Walkthrough

mootools each not iterating for me

I'm going nuts here but the each function is just not working for me.
I have about 20 elements with a class name of "lookup" (text boxes) and this function successfully turns all elements red:
document.addEvent('domready', function()
{
var tb = $$('.lookup');
tb.setStyle("color", "red");
});
However, in the following code, I would expect to get some alert for each element but the alert don't hit at all, and no exception is raised either. It is like the each is iterating through 0 items....
document.addEvent('domready', function()
{
var tb = $$('.lookup');
tb.each(function(el)
{
alert("hi");
});
});
Any idea what I might be doing wrong?
In both examples above, I used $$('.lookup').each and $$('.lookup').setStyle() with the same outcome (example 1 works; example 2 doesn't).
Thanks in advance.
Which browsers have problems? Try use 'window' instead 'document'
window.addEvent('domready', function(){
var tb = $$('.lookup');
tb.each(function(el){
el.setStyle("color", "red");
alert("hi");
});
});
In mootools better always use 'each' for working with array of elements.
I've discovered that reordering the mootools include script so that it is referenced after the Microsoft WebResource.axd?d= include script resolves the problem. Mootools appears to handle the conflict, whereas Microsoft ASP.NET can't.

IE9 HTML5 placeholder - how are people achieving this?

I'm trying to use the placeholder="xxx" attribute in my web application, and I don't want to have a special visual for IE9. Can people throw out some good suggestions for achieving this functionality in IE9?
I've found a couple links on here but none of the suggested scripts were sufficient... and the answers were from mid-2011, so I figured maybe there is a better solution out there. Perhaps with a widely-adopted jQuery plugin? I do not want to use anything that requires intrusive code such as requiring a certain css class or something.
Thanks.
EDIT - I also need this to work for password input fields.
// the below snippet should work, but isn't.
$(document).ready(function() {
initPlaceholders()();
}
function initPlaceholders() {
$.support.placeholder = false;
var test = document.createElement('input');
if ('placeholder' in test) {
$.support.placeholder = true;
return function() { }
} else {
return function() {
$(function() {
var active = document.activeElement;
$('form').delegate(':text, :password', 'focus', function() {
var _placeholder = $(this).attr('placeholder'),
_val = $(this).val();
if (_placeholder != '' && _val == _placeholder) {
$(this).val('').removeClass('hasPlaceholder');
}
}).delegate(':text, :password', 'blur', function() {
var _placeholder = $(this).attr('placeholder'),
_val = $(this).val();
if (_placeholder != '' && (_val == '' || _val == _placeholder)) {
$(this).val(_placeholder).addClass('hasPlaceholder');
}
}).submit(function() {
$(this).find('.hasPlaceholder').each(function() { $(this).val(''); });
});
$(':text, :password').blur();
$(active).focus();
});
}
}
}
We just researched the same thing. We decided on reusing this gist, by Aaron McCall, after making some minor changes. The main advantage is that it's simple, easy to understand code:
Remove the kernel and setup_placeholders parts. Just call it immediately in an anonymous function.
Add var before test.
For browsers that support placeholder, it simply falls back to that. It also handles new input elements (note the use of delegate) in existing forms. But does not handle dynamic new form elements. It could probably be modified to do so with jQuery.on.
If you don't like this one, you can use one of the ones here. However, some of them are overcomplicated, or have questionable design decisions like setTimeout for detecting new elements.
Note that it needs to use two pairs of parens, since you're calling an anonymous function, then calling the returned function (this could be factored out differently):
(function () {
// ...
})()();
I wrote a jquery plugin a while back that adds the placeholder support to any browser that does not support it and does nothing in those that do.
Placeholder Plugin
Here's a jQuery plugin that works with password fields as well. It's not as tiny as the code suggested by Matthew but it has a few more fixes in it. I've used this successfully together with H5Validate as well.
http://webcloud.se/code/jQuery-Placeholder/

Unknown macro in library

I am trying to make a library, went well so far, but after adding a few functions it went bad.
When I run the script form the editor it is written in the script works. But when I try to test it the script cannot recognize the server handlers, giving an error: Unknown macro handler_function_name
I checked, all the names in the handlers correspond to names of functions. I read that some people had problems because the code was in different files, moved all the code in the same file the problem is still there.
It does not behave like that for all the handlers...
What else could be the reason for this?
edit:
The app creates additional panels during as a response to "clicks". Handlers of elements on those panels are the ones who's macros (that is handler functions) the app is not able to "find".
How can this be solved?
(except for the solution to put all the panels in the original panel and then change visibility, this works as far as handlers go but raises other problems)
So to put some code here, this is very very simple code...
function notWorkingGUI(){
var app=UiApp.createApplication();
var appPanel=app.createVerticalPanel().setId("appPanel");
var handler1=app.createServerHandler("handlerFunction1").addCallbackElement(appPanel);
var firstButton=app.createButton("Button 1", handler1);
appPanel.add(firstButton);
app.add(appPanel);
SpreadsheetApp.getActive().show(app);
}
function handlerFunction1(e){
var app=UiApp.getActiveApplication();
var appPanel2=app.createVerticalPanel().setId("appPanel2").setStyleAttribute("zIndex", 0).setStyleAttribute("position", "fixed");
var handler2=app.createServerHandler("handlerFunction2").addCallbackElement(appPanel2);
var secondButton=app.createButton("Button 2", handler2);
var label=app.createLabel("This should get visible after the click").setId("label").setVisible(false);
appPanel2.add(secondButton).add(label);
app.add(appPanel2);
return app;
}
function handlerFunction2(e){
var app=UiApp.getActiveApplication();
app.getElementById("label").setVisible(true);
return app;
}
This will work as expected when executed from the editor in which it is written, that is it will show firstButton then secondButton and finaly the label, however if it would be published as a library and invoked from an other script it would only recognise functionHandler1, that is show firstButton, secondButton but after a click on the secondButton an error message will be seen.
However if the script would be written like this:
function workingGUI(){
//previous first part
var app=UiApp.createApplication();
var appPanel=app.createVerticalPanel().setId("appPanel");
var handler1=app.createServerHandler("handlerFunction1a").addCallbackElement(appPanel);
var firstButton=app.createButton("Button 1", handler1);
//previous second part
var appPanel2=app.createVerticalPanel().setId("appPanel2").setStyleAttribute("zIndex", 0).setStyleAttribute("position", "fixed");
var handler2=app.createServerHandler("handlerFunction2a").addCallbackElement(appPanel2);
var secondButton=app.createButton("Button 2", handler2).setId("button2");
appPanel.add(firstButton);
app.add(appPanel);
SpreadsheetApp.getActive().show(app);
}
function handlerFunction1a(e){
var app=UiApp.getActiveApplication();
var label=app.createLabel("This should get visible after the click").setId("label").setVisible(false);
app.getElementById("appPanel2").add(app.getElementById("button2")).add(label);
app.add(app.getElementById("appPanel2"));
return app;
}
function handlerFunction2a(e){
var app=UiApp.getActiveApplication();
app.getElementById("label").setVisible(true);
return app;
}
Note that all handlers must be defined in the main function, meaning that also all the elements using those handlers and all the callback elements have to be defined here.
Then it would work even as a library, however for some reason this makes the script much much slower even for such a simple example.
The issue is here:
http://code.google.com/p/google-apps-script-issues/issues/detail?id=1346
It is calling the local code rather than the library code.
I wonder if it is still slow if you add a stub function in the local code?
i.e.
function runthis() {
library.createGUI();
}
function myevent() {
library.myevent();
}
I worked around this problem, it makes the script a bit slower but if you define all the handlers (that implies all the UI elements) in the original function it will work.

Why does not jQuery.live function work with static elements?

I have a dynamic HTML table, where I can add and remove rows.
Each row contains a button that has a class removeRow.
In my JavaScript, I have:
$('button.removeRow').live("click", function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
The problem is that it works for all buttons that belong to rows that were inserted after the page was loaded (by clicking on 'Add row' button).
It works for existing buttons, only if I change the above code to (but then it does not work for dynamically added rows):
$('button.removeRow').click(function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
I think that the live function should work for both, so can you point me into the right direction? Where can it go wrong?
OK I found a bug today. Somewhere in my code I had:
$('input[type=submit], button').click(function () {
return false;
});
I wanted it to work with the submit button, so it would not submit the form on click. I do not remember why I put button there. Anyways, because of that my static button clicks were attached this event, while dynamically created ones were not. Therefore live 'click' worked for dynamic buttons. Stupid mistake...
Hacky solution: Do both
$('button.removeRow').live("click", function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
and
$('button.removeRow').click(function () {
var row = $(this).parents('tr')
row.remove();
return false;
});
It would be helpful if you posted some example HTML as well as the code responsible for inserting new rows, though.
Maybe something is going wrong if other tr elements are matched by your .parents() selector. Try .closest():
$('button.removeRow').live("click", function(){
$(this).closest('tr').remove();
return false;
});
The live should work for both dynamic and pre-rendered elements.
I'd start by working out if that content really exists before that jQuery is run...Try outputting the result of the following somewhere, or use the debugger keyword, or even the dreaded alert:
$('button.removeRow').length
// The rest of your click handler definition...