Im trying to place an inner div to my resizable handle, but it renders the handle useless.
<div class="layer" style="width: 150px;">
<div class="left ui-resizable-handle ui-resizable-w">
<div><<< div</div>
</div>
<div class="right ui-resizable-handle ui-resizable-e">>>></div>
</div>
$('.layer').resizable({
handles: null
});
http://jsfiddle.net/MatteS75/3dwVp/15/
How can I make this work?
changing the _mouseCapture method in the jquery ui resizable widget to this makes it work:
_mouseCapture: function(event) {
var capture = false;
for (var i in this.handles) {
var handle = $(this.handles[i])[0];
if (handle == event.target || $.contains(handle, event.target)) {
capture = true;
}
}
return !this.options.disabled && capture;
},
I also created a ticket and pull request for this:
http://bugs.jqueryui.com/ticket/8756
Related
QUESTION
How can I use PropertiesService to store an array from index.html, send the array to code.gs, and return the array in index.html?
SPECIFIC CASE
In a Google Web App, I have a group of sortable lists (made using JQuery UI Sortable). I want to save the most recent order/position of each li. I'm attempting to have that order/position "persist" when the page is refreshed or closed.
EXAMPLE
If you see the default Sortable, you could change the order of the items. If you refreshed the page, or closed it and return, the items would be in their original order.
WHERE I'M HAVING TROUBLE
I am able to get the array to show up in the console, but I don't know how to get it back to code.gs. I think I am now, but I'm not sure. Beyond that, I don't know how to "read" that PropertiesService so that the array is returned to index.html. I'm not really sure what I'm doing so if someone could slow walk me it would be appreciated!
ALTERNATIVES
I also looked into writing directly to the spreadsheet where the values originate. I'm not really sure how to do that either. I made some attempts, and was able to get "undefined" as a value in a spreadsheet cell.
FULL CODE (note: the list items are formed using an array, so they will not show up here): https://jsfiddle.net/nateomardavis/Lmcjzho2/1/
PARTIAL CODE
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('index');
}
function webAppTest() {
getTeamArray();
}
function getTeamArray() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('TEST');
var range = sheet.getRange(2, 1, 1000, 1);
var values = range.getValues();
var teamsArray = [];
for (var i = 0; i < values.length; ++i) {
teamsArray.push(values[i][0]);
}
var uniqueArray = [];
uniqueArray.push(teamsArray[0]);
for (var i in teamsArray) {
if ((uniqueArray[uniqueArray.length - 1] != teamsArray[i]) && (teamsArray[i] !== "")) {
uniqueArray.push(teamsArray[i]);
}
}
return uniqueArray;
}
function savePositions(myProperty, positions) {
PropertiesService.getScriptProperties().setProperty("myProperty", JSON.stringify(positions));
};
function getPositions() {
var returnedObj = PropertiesService.getScriptProperties()
};
index.html
<body>
<div id="myList" class="connectedSortable">MY LIST</div>
<table id=table1>
<div id="team1">
<p>TEAM 1</p>
<br>
<div id="group" v>SELECTED</div>
<ul id="team1s" name='team1s' class="connectedSortable"></ul>
<div id="group">ALTERNATE</div>
<ul id="team1a" name='team1a' class="connectedSortable"></ul>
</div>
</table>
<table id=table2>
<div id="team2">
<p>TEAM 2</p>
<br>
<div id="group" v>SELECTED</div>
<ul id="team2s" name='team2s' class="connectedSortable"></ul>
<div id="group">ALTERNATE</div>
<ul id="team2a" name='team2a' class="connectedSortable"></ul>
</div>
</table>
<table id=table3>
<div id="team3">
<p>TEAM 3</p>
<br>
<div id="group" v>SELECTED</div>
<ul id="team3s" name='team3s' class="connectedSortable"></ul>
<div id="group">ALTERNATE</div>
<ul id="team3a" name='team3a' class="connectedSortable"></ul>
</div>
</table>
<table id=table4>
<div id="team4">
<p>TEAM 4</p>
<br>
<div id="group" v>SELECTED</div>
<ul id="team4s" name='team4s' class="connectedSortable"></ul>
<div id="group">ALTERNATE</div>
<ul id="team4a" name='team4a' class="connectedSortable"></ul>
</div>
</table>
<script>
$(function() {
google.script.run.withSuccessHandler(buildOptionsList)
.getTeamArray();
});
function buildOptionsList(uniqueArray) {
var div = document.getElementById('myList');
for (var i = 0; i < uniqueArray.length; i++) {
var ul = document.createElement('ul');
var li = document.createElement('li');
var cLass = li.setAttribute('class', 'ui-state-default');
var iD = li.setAttribute('id', uniqueArray[i]);
li.appendChild(document.createTextNode(uniqueArray[i]));
div.appendChild(ul);
div.appendChild(li);
}
}
$(function() {
$("#myList, #team1s, #team1a, #team2s, #team2a, #team2s, #team3s, #team3a, #team4s, #team4a").sortable({
connectWith: ".connectedSortable",
update: function(event, ui) {
var changedList = this.id;
var order = $(this).sortable('toArray');
var positions = order.join(';');
console.log({
id: changedList,
positions: positions
});
//Instead of using JSON to save, can I use the spreadsheet itself to save the positions and then pull it from there as I did with "buildOptionsList" above?
function saveList() {
google.script.run.savePositions("myProperty", JSON.stringify(positions));
JSON.parse("myProperty");
}
}
})
});
$(function getPositions(event, ui) {
var changedList = this.id;
var order = $(this).sortable('toArray');
var positions = order.join(';');
console.log({
id: changedList,
positions: positions
});
});
</script>
</body>
</html>
It's also possible to just use the browser's localStorage client side.
localStorage.setItem('id', positions); //Store positions in users browser
localStorage.getItem('id'); //Retrieve the stored positions later
Notes:
For this to work, the url(document.domain of the iframe="*.googleusercontent.com") from which your script is deployed must remain constant. During my brief testing, it was constant even when changing from /dev to /exec of the parent(script.google.com) and even during version update. But there's no official reference.
This solution is better than properties service, if you have multiple users, as each one will have their own data stored in their own browsers and there are no server calls during each change.
Using google.script.run simple example:
<script>
function sendStringToServer() {
var string=$('#text1').val();
google.script.run
.withSuccessHandler(function(s){
alert(s);
})
.saveString(string);
}
</script>
Google Script:
function myFunction() {
PropertiesService.getScriptProperties().setProperty('MyString', string);
return "String was saved in Service";
}
Client to Server Communication
My form I am designing with MVC 4 has mutiple DIVS with many elements in each one. My objective is to open/close DIVS as the user completes the fields. However, I want to use the unobtrusive validation on each DIV, rather than the whole form. Is that possible without checking each element individually? Maybe using a DIV ID or something? I don't want to build this massive function to check each and every element in each DIV just so the user can move to the next DIV.
I am trying this and it is not working:
var elems = [];
var valid = true;
("#Contact").find('.text_input').each(function() {
elems.push(this.id);
}
for (var i = 0; i<= elems.length; i++) {
if ($("#" + elems[i]) != undefined) {
$("#form1").validate().element("#" + elems[i]))
if ($("#" + elems[i]).valid()) {
}
else {
valid = false;
}
}
}
but I keep getting an undefined error. The elements in the DIV that have the class text_input are the ones with validation required.
You can validate individual controls using Validator.element(element) - see documentation here, so you could use the following approach (you haven't posted the views html so can't write the actual code for you)
In the Next button click event
Select all the the controls within the
associated div - e.g. var controls = $(this).closest('div').find('input, textarea, select');
In an $.each loop, call $("form").validate().element($(this));
If necessary, test if valid with $(this).valid();
If everything is valid, hide the current div and display the next
Edit (example added)
View
<div class="section">
<h2>Section 1</h2>
.... // Your inputs and validation
#Html.LabelFor(m => m.SomeProperty)
#Html.TextBoxFor(m => m.SomeProperty)
#Html.ValidationMessageFor(m => m.SomeProperty)
<div class="error"></div>
<button type="button" class="next">Next</button>
</div>
<div class="section">
<h2>Section 2</h2>
.... // Your inputs and validation
<div class="error"></div>
<button type="button" class="next">Next</button>
</div>
<div class="section">
<h2>Section 3</h2>
.... // Your inputs and validation
<div class="error"></div>
<button type="submit" class="next">Submit</button> // submit button for last section
</div>
CSS
.section:not(:first-of-type) {
display:none;
}
Script
$('button').click(function () {
var container = $(this).closest('.section');
var isValid = true;
$.each(container.find('input'), function () {
$('form').validate().element($(this));
if (!$(this).valid()) {
isValid = false;
return false;
}
});
if (isValid) {
container.next('.section').show().find('input').first().focus();
container.hide();
} else {
container.find('.error').text('please complete');
}
});
I read over 20 different articles and forum topics about that, tried different solutions but I didn't cope with it.
The following code doesn't work. I need someone's help...
LoginView.js
var LoginView = Backbone.View.extend({
//el: $('#page-login'),
initialize: function() {
_.bindAll(this, 'gotoLogin', 'render');
//this.render();
},
events: {
'click #button-login': 'gotoLogin'
},
gotoLogin : function(e){
e.preventDefault();
$('#signup-or-login').hide();
$('#login').show();
return true;
}
});
login.html
<div data-role="page" id="page-login">
<!-- SignUp or Login section-->
<div id="signup-or-login" data-theme="a">
<a data-role="button" data-theme="b" id="button-signup"> Sign Up </a>
<a data-role="button" data-theme="x" id="button-login"> Login </a>
</div>
<!-- Login section-->
<div id="login" data-theme="a">
<button data-theme="b"> Login </button>
<button data-theme="x"> Cancel </button>
</div>
</div>
The page is created in method of Backbone.Router extended class.
loadPage('login.html', new LoginView());
From what I understand, $.mobile.loadPage() grabs the desired html and attaches it to the DOM.
Currently, you're trying to set el after the View has been instantiated.
However, notice that Backbone.View attaches el and $el when it's instantiated:
var View = Backbone.View = function(options) {
...
this._ensureElement();
this.initialize.apply(this, arguments);
this.delegateEvents();
};
Also notice that View.setElement() sets $el by passing a selector or a jQuery objected to View.el:
setElement: function(element, delegate) {
if (this.$el) this.undelegateEvents();
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
this.el = this.$el[0];
if (delegate !== false) this.delegateEvents();
return this;
}
Bottom line:
You need to set el (in your case with the provided jQuery object) while instantiating it:
// Where `view` is a reference to the constructor, not an instantiated object
var loadPage = function(url, view) {
$.mobile.loadPage(url, true).done(function (absUrul, options, page) {
var v,
pageId = page.attr('id');
v = new view({
el: page
});
...
}
}
You now call loadPage() like so:
loadPage('login.html', LoginView);
This gives Backbone.View the $el which to delegate your events.
I have a below custom directive in angularjs which uses model thats gets updated from server,
I have added a watch listener to watch the changes of that model,
var linkFn;
linkFn = function(scope, element, attrs) {
scope.$watch('$parent.photogallery', function(newValue, oldValue) {
if(angular.isUndefined(newValue)) {
return;
}
var $container = element;
alert($container.element);
$container.imagesLoaded(function() {
$container.masonry({
itemSelector : '.box'
});
});
});
};
return {
templateUrl:'templates/Photos_Masonry.htm',
replace: false,
transclude:true,
scope: {
photogallery: '=photoGallery',
},
restrict: 'A',
link: linkFn
However, when i debug in my watch directive, i still see that expressions in templates are still unresolved.i.e. photo.label, ng-src all are still unresolved. AFIK, $digest would be called only after $eval. Is this intended behavior?
My jQuery calls are not working due to this? Is there any other event where i get the result element with evaluated expressions?
Here is my template, which has ng-repeat in it,
<div id="container" class="clearfix">
<div class="box col2" ng-repeat="photo in photogallery">
<a ng-href="#/viewphotos?id={{photo.uniqueid}}&&galleryid={{galleryid}}"
title="{{photo.label}}"><img
ng-src="{{photo.thumbnail_url}}" alt="Stanley" class="fade_spot" /></a>
<h3>
<span style="border-bottom: 1px solid black;font-weight:normal;font-size:14px;">{{galleryname}}</span>
</h3>
<h3>
<span style="color:#20ACB8;font-weight:normal;font-size:17px;">{{photo.seasonname}}</span>
</h3>
</div>
</div>
photogallery is initialized in parent controller,
function MyCtrlCampaign($scope, srvgallery, mygallery) {
$scope.updatedata = function() {
$scope.photogallery = srvgallery.getphotos($routeParams);
};
$scope.getphotos = function() {
srvgallery.photos().success(function(data) {
$scope.updatedata();
}).error(function(data) {
});
};
Directive is used in below way,
<div masonry photo-gallery="photogallery" >
</div>
Kindly let me know your views on this.
Looks like this has been resolved in your Github issue (posted for the convenience of others).
var modify = document.queryAll("#tab");
for(var i=0; i<modify.length; i++)
{
modify[i].on.click.add((Event e) => show_content(i));
}
// code for hide_content()
i have two function show_content() and hide_content() that operates on the div's
i'm not able to detect second time click on a div to trigger hide_content(). i've tried with a semaphore and - no luck
<div id="tab"> </div>
<div id="content"> </div>
<div id="tab"> </div>
<div id="content"> </div>
queryAll is used for non-unique elements. Using queryAll for an unique element with the ID tab doesn't make any sense. You should use query('#tab') where you get just a single DivElement as its return value.
However I'm not sure, I undersand your problem but if you need a toggle button, you're maybe looking for something like this:
DivElement uniqeDiv;
void toggle() {
if(uniqeDiv.hidden) {
// uniqeDiv.hidden = false;
show();
} else {
// uniqeDiv.hidden = true;
hide();
}
}
void main() {
uniqeDiv = query('#tab');
uniqeDiv.on.click.add((Event e) => toggle());
}