I seem to make a mistake in the following:
html: index.html, main.html, etc
js: jQuery, jQuery UI, own.js, own_main.js
The end result should be an index page that based on a menu choice loads a html in a div.
The HTML that loads has a button element that I want to use with jQuery UI.
Index.html
<html lang="us">
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Dev</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="css/kendo.dataviz.default.min.css" rel="stylesheet" />
<link href="css/kendo.dataviz.min.css" rel="stylesheet" />
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<link href="css/jquery-ui-1.10.3.custom.css" rel="stylesheet">
<link href="css/typ.css" rel="stylesheet" />
<script src="js/modernizr-2.6.2-respond-1.1.0.min.js"></script>
<script src="Scripts/jquery-2.0.3.js"></script>
<script src="js/jquery-ui-1.10.3.custom.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/typ.js"></script>
<script src="js/typ-persons.js"></script>
</head>
<body>
<div id="content"></div>
</body>
</html>
typ.js file
function currentLoc(goToLoc) {
if (CheckLogin() == 0) {
//Not logged in, go to main
$("#content").load("/main.html");
window.localStorage.globalLocation = "/main.html";
} else {
if (goToLoc == '') {
console.log("No GoToLoc: " + goToLoc);
if (window.localStorage.globalLocation == '') {
console.log("No Global location");
$("#content").load("/main.html");
window.localStorage.globalLocation = "/main.html";
} else {
console.log("Global Location " + window.localStorage.globalLocation);
$("#content").load(window.localStorage.globalLocation);
}
} else {
console.log("GoToLoc " + goToLoc);
$("#content").load(goToLoc);
window.localStorage.globalLocation = goToLoc;
}
}
}
persons.html
<script src="js/typ-persons.js"></script>
<div class="container">
<style>
#toolbar {
padding: 4px;
display: inline-block;
}
/* support: IE7 */
* + html #toolbar {
display: inline;
}
</style>
<div id="toolbar" style="width:100%;" class="ui-widget-header ui-corner-all">
<button id="btnNew" ></button>
<button id="btnSave"></button>
<label for="persons">Find Person by Name or ID: </label>
<input type="text" class="input-sm" id="persons">
<input type="hidden" id="person-id">
</div>
</div>
typ-persons.js
$(function () {
$("#btnNew").button({
text: false,
label: "New Person",
icons: {
primary: "ui-icon-document"
}
})
.click(function () {
});
$("#btnSave").button({
text: false,
label: "Save",
disabled: true,
icons: {
primary: "ui-icon-disk"
}
})
.click(function () {
});
});
On the persons page there is also an autocomplete element with json data.
This works like a charm.
The problem is that the toolbar does not get the buttons applied from the typ-persons.js.
When I add the jQuery UI to the persons.html the buttons do work and get styled as they are supposed to.
The problem then is that jQuery UI loads twice and the autocomplete drowdown disappears on mouse over.
Kind of a paradox here and I would like both to work.
Thanks for your help,
Joris
I have the hunch that your persons.html file is the main.html addressed in the code. Otherwise I can't see where do you load persons.html or what are you loading when you load main.html.
Why are you adding typ-persons.js to persons.html, if you already have it in your main html file? In the way it's added, there's going to be double binding on button clicks. More than once, I believe. It would work on first load and then screw button behavior for good.
EDIT: After OP clarifications, these are my suggestions.
First: instead of putting new JS into persons html, make it just plain html. Make sure you don't use id attributes when that content is prone to be loaded several times. In that case, it's best to use classes.
<div class="container">
<style>
#toolbar {
padding: 4px;
display: inline-block;
}
/* support: IE7 */
* + html #toolbar {
display: inline;
}
</style>
<div id="toolbar" style="width:100%;" class="ui-widget-header ui-corner-all">
<button class="btnNew" ></button>
<button class="btnSave"></button>
<label for="persons">Find Person by Name or ID: </label>
<input type="text" class="input-sm" id="persons">
<input type="hidden" id="person-id">
</div>
</div>
Second: since you won't load new JS in that ajax call, you need to give the new buttons their behavior somewhere, right? Try to do that after they're appended, using jQuery's callback. I'd reccomend you use get method instead of load to have a bit more control on new content. Instead of
$("#content").load("/persons.html");
Try
$.get("/persons.html",function(responseText) {
var newElement=jQuery(responseText);
$("#content").append(newElement);
$(".btnNew", newElement).button({
text: false,
label: "New Person",
icons: {
primary: "ui-icon-document"
}
}).click(function () {
});
$(".btnSave",newElement).button({
text: false,
label: "Save",
disabled: true,
icons: {
primary: "ui-icon-disk"
}
}).click(function () {
});
});
Third: whatever listener you need to be set on dynamic elements, delegate them to the document to avoid needing to redeclare it (with the risk of double binding). I see no examples of this in your original post, but if you have any case of click, focus, or blur listeners (to name a few) I'll include a practical example.
Related
I am trying to display a dialog box when users access a page with a device smaller than a desktop. I am not an expert in jQuery. I tried the following below but was not successful.
$(document).ready(function () {
if (window.matchMedia('(max-width: 767px)').matches) {
var dialog = $("#ScreenSize").dialog({
modal: true,
autoopen: true,
}).show();
} else {
$("ScreenSize").dialog().hide();
}
});
<div id="ScreenSize" style="display:none">
<p>Go to Text Box</p>
</div>
This code is executed on Dom ready. Considering that you open that dialog only in the if branch, actually the else branch is useless because when you reload the page, it doesn't get opened at all. Or maybe there is some other logic that you are not providing.
Then .dialog() is a method of the jQuery UI library. You should add also that library in order to get the dialog working. If you open your console you see that the method dialog() is undefined.
Your javascript code is OK. On the html part, jQuery and jQuery UI (for the dialog widget) scripts must be loaded in the correct order: jQuery first, UI after. Try the following code snippet, it works as you wanted.
$(document).ready(function () {
if (window.matchMedia('(max-width: 767px)').matches) {
var dialog = $("#ScreenSize").dialog({
modal: true,
autoopen: true
}).show();
} else {
// this part is useless...
$("ScreenSize").dialog().hide();
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<div id="ScreenSize" style="display:none">
<p>Go to Text Box</p>
</div>
</body>
</html>
Why is jQuery needed? Why not just use css media query to display and hide your dialog box.
CSS:
#ScreenSize {
display: none;
}
#media only screen and (max-width: 767px) {
#ScreenSize {
display: block;
}
}
i have used these following below in order to find a solution to my problem
$(function () {
if (screen.width < 1023) {
$("#ScreenSize").show();
var dialog = $("#ScreenSize").dialog({
modal: true,
autoopen: true,
resizable: false, draggable: false,
})
}
else {
$("#ScreenSize").hide();
}
});
<span class="ui-state-default ui-corner-all" style="float: left; margin: 0 7px 0 0;"><span class="ui-icon ui-icon-info" style="float: left;"></span></span>
<div style="margin-left: 23px;">
<p>go to Text Box</p>
</div>
<//div>
I'm far from an expert on Angular, so I have to try asking a question here. I've added the possibility to upload files in may AngularJS project. I need to display the selected filename in a textbox (or preferably a read-only field) before the user submits the form. It contains a number of fields that need validation. The problem is, the selected filename never shows up. The textblock is still empty after selecting a file. I've tried the following code (Plunker: http://plnkr.co/edit/Ll3GZdpp8Tsqwvo0W1ax):
index.html:
<!DOCTYPE html>
<html ng-app="myApp">
<head lang="en">
<meta charset="utf-8" />
<title>Custom Plunker</title>
<script data-require="jquery#2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<link data-require="bootstrap#*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
<script data-require="bootstrap#*" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="http://angular-ui.github.com/ng-grid/css/ng-grid.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<script type="text/javascript" src="http://angular-ui.github.com/ng-grid/lib/ng-grid.debug.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
<body ng-controller="MyCtrl">
<div class="row">
<div class="col-md-12">
<span class="btn btn-default btn-file">
Välj fil... <input type="file" onchange=" angular.element(this).scope().setFile(this) ">
</span>
<input type="text" ng-model="organizationSettings.logotypeFileName" />
</div>
</div>
</body>
</html>
app.js:
var app = angular.module('myApp', []);
app.controller('MyCtrl', function($scope) {
$scope.organizationSettings = {};
$scope.setFile = function(element) {
$scope.fileToUpload = element.files[0];
console.log($scope.fileToUpload.name);
$scope.organizationSettings.logotypeFileName = $scope.fileToUpload.name;
};
});
css:
.btn-file {
position: relative;
overflow: hidden;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
outline: none;
background: white;
cursor: inherit;
display: block;
}
The reason is you are using onchange which is an event outside of any of angular's directives.
Whenever you use an event outside of angular that changes the scope, you need to notify that a digest is needed to update the part of the view managed by that scope by using $apply
The simplest fix is to use ng-change instead of native onchange. All of angulars event handling directives will trigger $apply internally
The alternative (not best approach) would be keep the onchange and do:
$scope.setFile = function(element) {
$scope.fileToUpload = element.files[0];
console.log($scope.fileToUpload.name);
$scope.organizationSettings.logotypeFileName = $scope.fileToUpload.name;
$scope.$apply();
};
You can't use ng-change for file upload because binding is not supported for file upload in angularjs., its an issue in angularjs.
In other cases while you are using ng-change(other than file upload) you have to use ng-model to make the ng-change directive work in order to trigger change based on it(so only you are getting "Error: No controller: ngModel") while using it.
The best possible solution is you manually trigger $scope.$apply() to make binding to the input model while programatically setting it.
I think that binding changes could be done easier, and I will explain below how to do it. By setting a ng-model to the input, it will automatically bind the input control to the variable defined in your controller's scope. Therefore, if you specify a new file, it will automatically update the model $scope.fileToUpload. This goes the other way around: any change in $scope.fileToUpload done in JS, will be reflected in the DOM.
index.html - try to replace
<input type="file" onchange=" angular.element(this).scope().setFile(this) ">
with
<input type="file" ng-model="fileToUpload">
In app.js, you could get rid of:
$scope.setFile = function(element) {
$scope.fileToUpload = element.files[0];
console.log($scope.fileToUpload.name);
$scope.organizationSettings.logotypeFileName = $scope.fileToUpload.name;
};
Problem
When I click the buttons for playoff season or regular, the divs that holds the content players-list and players-regular appear to jump out of place when they fade in and out. How do I prevent this from happening?
I've tried using position fixed on some of elements, but things would get way out of place. I've included a JSFiddle here: http://jsfiddle.net/onlyandrewn/gcthaffs/
Click listener
// Click listener, toggles between sheets
$('button').click(function() {
$('button').removeClass("active");
$(this).toggleClass("active");
if ($('button.regular').hasClass('active')) {
$('#players-list').fadeOut(500);
$('.note').fadeOut(500);
$('#players-regular').fadeIn(2000);
} else {
$('#players-regular').fadeOut(500);
$('#players-list').fadeIn(2000);
$('.note').fadeIn(2000);
}
});
index.html
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="UTF-8">
<title>Wheat Kings' leading point scorers</title>
<meta name="description" content="Wheat Kings' leading point scorers">
<meta name="author" content="Andrew Nguyen">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="assets/css/style.css">
<link href='http://fonts.googleapis.com/css?family=Lato:300,400,700,900' rel='stylesheet' type='text/css'>
</head>
<body>
<h1>Wheat Kings leading goal scorers</h1>
<p class="year"></p>
<button class="playoffs active">Playoffs</button>
<button class="regular">Regular Season</button>
<div class="top">
<div id="players-list"></div>
<div id="players-regular"></div>
<p class="note">Note: Since there was a five-way tie for 6th place, players who scored two goals were then ranked by their total points in the playoffs. The other two players not listed here are Nolan Patrick and Macoy Erkamps.</p>
</div><!-- /.top -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.3.5/tabletop.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.0/handlebars.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.js"></script>
<!-- This is where the template for facts goes -->
<script id="players" type="text/x-handlebars-template">
<div class="container">
<div class="group">
<div class="{{row}}">
<p class="goals">{{goals}}</p>
<img src="{{image}}" alt="" class="head">
<p class="name">{{name}}</p>
<p class="position">{{position}}</p>
</div><!-- /.group -->
</div><!-- /.row -->
</div><!-- /.container -->
</script>
<script type="text/javascript">
// Click listener, toggles between sheets
$('button').click(function() {
$('button').removeClass("active");
$(this).toggleClass("active");
if ($('button.regular').hasClass('active')) {
$('#players-list').fadeOut(500);
$('.note').fadeOut(500);
$('#players-regular').fadeIn(2000);
} else {
$('#players-regular').fadeOut(500);
$('#players-list').fadeIn(2000);
$('.note').fadeIn(2000);
}
});
// Original
var public_spreadsheet_url = "https://docs.google.com/spreadsheets/d/1RMN49oyRlTxW5kv8MnYJwQRttis2csgVFH46kyORCaQ/pubhtml";
$(document).ready( function() {
Tabletop.init( { key: public_spreadsheet_url,
callback: showInfo,
parseNumbers: true } );
});
function showInfo(data, tabletop) {
var source = $("#players").html();
var template = Handlebars.compile(source);
// The actual name of the sheet, not entire .csv
$.each(tabletop.sheets("Playoffs").all(), function(i, fact) {
var html = template(fact);
// You need an element with this id or class in your HTML
$("#players-list").append(html);
$('.container').eq(i).addClass(data.Playoffs.elements[i]);
// This logs all the objects in the sheet
// console.log(data);
// This logs just validity
// console.log(data.Playoffs.elements[i]);
})
// If you need to get data from a second sheet in single Google Doc
$.each(tabletop.sheets("Regular").all(), function(i, fact) {
var html = template(fact);
// You need an element with this id or class in your HTML
$("#players-regular").append(html);
$('.container').eq(i).addClass(data.Regular.elements[i]);
// This logs all the objects in the sheet
// console.log(data);
// This logs just validity
// console.log(data.Regular.elements[i]);
});
}
</script>
</body>
</html>
base.scss
/*----------------------------------
MAIN STYLES
----------------------------------*/
html {
font-size: 62.5%; /* 10px browser default */
}
body {
max-width: 600px;
padding: 10px;
}
.top {
max-width: 600px;
}
#players-list,
#players-regular {
}
h1 {
font-family: 'Lato', sans-serif;
font-weight: 900;
border-bottom: 1px solid #ccc;
padding-bottom: 8px;
}
.note {
position: relative;
width: 95%;
left: 3%;
}
This is happening because the fadeOut is not done when the fadeIn starts. You end up with both divs visible for a short period of time, and when the fadeOut is done the first div is hidden and you see the jump.
How about something like this:
$('#players-list').fadeOut(500, function() {
$('#players-regular').fadeIn(500);
});
This way the second div is displayed only when the first one is completely hidden.
Also, decrease the animation duration a bit, it makes for better user experience ;).
So I'm adding an Elessar slider (found at https://github.com/quarterto/Elessar) to a website I'm working on. However I wanted to use more than one instance of it. The problem is that if I attempt to add a duplicate of the slider div, or more than two, only the last one will function (the others act like empty containers). I have sifted through similar questions in stack exchange, and so far the question
jQuery sliders: only last slider working on page with multiple sliders
is the closest to my issue. I've tried to fix my problem by
1) Copying and pasting the function statement for each div with their own unique variable,
2) Inserting the script
$( ".slider1" ).clone().appendTo( ".slider1" );
to the existing script to clone the same div more than once (a resolution suggestively found in the link above), and
3) Including the script
$(document).ready(function()
{
$('new').append("<div class='slider1'>"+r+"</div>");
});
in the existing script to append the slider properties to a new div.
But none of these have had luck. The existing html is
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Elessar Slider</title>
<script type="text/javascript" src="../../JS/jquery/jquery.js"></script>
<script src="../../elessar/dist/elessar.js" type="text/javascript"></script>
<link rel="stylesheet" href="../../elessar/elessar.css">
<script src="../../elessar/moment/moment.js"></script>
<script src="stylesheet" src="../../elesser/bootstrap/dist/js/bootstrap.js" type="text/javascript"></script>
<link rel="stylesheet" href="../../elesser/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="../../elesser/bootstrap/dist/css/bootstrap-responsive.css">
<style>
body {
font-family: Arial, sans-serif;
}
h1, h2 {
font-family: Arial, sans-serif;
font-weight: 100;
}
h1 {
font-size: 60px;
}
.elessar-handle {
opacity: 0.1;
}
header .pull-right {
margin: 10px 0 0 10px;
padding: 9.5px;
}
</style>
</head>
<body>
<!--Div to be copied--!>
<div style="width: 650px;">
<div class="slider1" class="container" role="main"></div>
</div>
<!----!>
<script>
var r = new RangeBar({
min: moment().startOf('day').format('LLLL'),
max: moment().endOf('day').format('LLLL'),
valueFormat: function (ts) {
return moment(ts).format('LLLL');
},
valueParse: function (date) {
return moment(date).valueOf();
},
values: [
[
moment().startOf('day').format('LLLL'),
moment().startOf('day').add(1, 'hours').format('LLLL')
],
[
moment().startOf('day').add(1.5, 'hours').format('LLLL'),
moment().startOf('day').add(3.5, 'hours').format('LLLL')
],
],
label: function (a) {
return moment(a[1]).from(a[0], true);
},
snap: 1000 * 60 * 15,
minSize: 1000 * 60 * 60,
barClass: 'progress',
rangeClass: 'bar',
allowDelete: true,
});
$('[role=main]').prepend(r.$el).on('changing', function (ev, ranges) {
$('pre.changing').html('changing ' + JSON.stringify(ranges, null, 2));
}).on('change', function (ev, ranges) {
$('pre.changing').after($('<pre>').html('changed ' + JSON.stringify(ranges, null, 2)));
});
</script>
</body>
</html>
The rest of the slider function is found within elessar.js linked at the top. I'm grateful for any help with this!
add different role attribute.
<body>
<div style="width: 650px;">
<div class="slider1" class="container" role="main"></div>
</div>
<div style="width: 650px;">
<div class="slider2" class="container" role="main1"></div>
</div>
</body>
Fiddle
To clarify: the role attribute in the demo isn't important, I'm just using it as a selector. When you copy the div you end up with two elements with the same role, and jQuery selects both. You could use classes instead.
(I have tightened up my original example)
I'm trying to invoke modal dialogs from within a tabbed UI, and I'm confused about the behavior I'm seeing. The first time I display the UI, my dialog behaves as expected, I can pull the data out of the fields, everything's wonderful.
tabtest2.html:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Tabtest 2</title>
<link rel="stylesheet" type="text/css" href="js/css/smoothness/jquery-ui-1.7.2.custom.css" media="screen"/>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function()
{
var tabs = $('#tabs').tabs({
load: function(event, ui)
{
initializeUI();
}
});
});
function initializeUI()
{
jQuery("#button1").click(function()
{
$(initializeUI.win).dialog("open");
});
$(initializeUI.win) = jQuery("#window1");
//instantiate the dialog
$(initializeUI.win).dialog({ height: 350,
width: 400,
modal: true,
position: 'center',
autoOpen:false,
title:'Create Agent',
overlay: { opacity: 0.5, background: 'black'},
buttons:
{
"Check Text 1": function()
{
var t1 = $("#text1");
alert("text 1 = " + t1.val());
},
"Close": function()
{
$(initializeUI.win).dialog("close");
}
}
});
}
</script>
</head>
<body>
<div id="tabs">
<ul>
<li>Tab1</li>
<li>Google</li>
</ul>
</div>
</body>
</html>
And tab1.html
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Tab 1</title>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.7.2.custom.min.js"></script>
</head>
<body>
<button id="button1" class="ui-button ui-state-default ui-corner-all">Button 1</button>
<div id="window1" style="display:none">
<form>
<fieldset>
<label for="text1">Text 1</label>
<input type="text" name="text1" id="text1" class="text ui-widget-content ui-corner-all" />
</fieldset>
</form>
</div>
</body>
</html>
This allows the dialog to (apparently) work on repeated tab selections, but when I try to change the contents of the text field and examine it, I get the old value (the value from the first invocation)!! It's as if I have created a new copy of the dialog and it's fields, but the original text field is sitting there unseen in the original dialog window, returning it's old results.
Obviously, there's a paradigm for handling these dialogs, divs and tabs that I haven't grasped yet. Anyone care to point out my errors?
In your example you are using the same remote content twice and more importantly, using the same ID in both tabs. After the content of the second page is loaded into the DOM, you will have two divs with the same ID. Since an ID is supposed to be unique on a page, the "old" values may simple be the values of the first div that javascript happens to find in the DOM.
You also appear to have two buttons with the id "button1"; one inside the modal div and one outside. This may also cause problems.
Using FireBug, I see that I create a new 'dialog' DIV element everytime I call InitializeUI(). So deleting the old DIVs seems to give me the desired results:
function initializeUI()
{
jQuery("#button1").click(function()
{
initializeUI.win.dialog("open");
});
initializeUI.win = jQuery("#window1");
// remove old 'dialog' DIV elements
$('div[role="dialog"]').each(function() {
$(this).remove();
});
//instantiate the dialog
$(initializeUI.win).dialog({ height: 350,
width: 400,
modal: true,
position: 'center',
autoOpen:false,
title:'Create Agent',
overlay: { opacity: 0.5, background: 'black'},
buttons:
{
"Check Text 1": function()
{
var t1 = $("#text1");
alert("text 1 = " + t1.val());
},
"Close": function()
{
initializeUI.win.dialog("close");
}
}
});
}