Stellar.js in RWD - responsive-design

I've been messing around with stellar.js. In my design, the navigation needs to become a select in order to save horizontal space.
I imagine the html would be similar to this :
<select>
<option data-slide="1">Accueil</option>
<option data-slide="2">Services</option>
<option data-slide="3">Réalisations</option>
<option data-slide="4">Contact</option>
</select>
However, I am not sure as to how the .js file should be changed in order to do this. I believe this is where the magic happens, but I am not 100% on this :
slide.waypoint(function (d, e) {
dataslide = c(this).attr("data-slide");
if (e === "down") {
c('.navigation li[data-slide="' + dataslide + '"]').addClass("active").prev().removeClass("active")
} else {
c('.navigation li[data-slide="' + dataslide + '"]').addClass("active").next().removeClass("active")
}
});
Has anyone ever done this ? Thanks !

I can tell by the code you posted that you're following the tutorial published a while a go in Tutsplus, right?
Well, that piece of Javascript code leverages the waypoint plugin to mark as selected the link corresponding to the slide in the viewport (and hence visually enhance it). But since you're going to be using a dropdown list the approach above is useless. To get things done you will need first to ensure that the user is properly scrolled upon changing the selectbox value. This will make the trick (you'd better change the jQuery selector below to ensure this handler does not affect any other input control in the page but the main dropdown nav widget):
$('select').on('change', function() {
var slide = $(this).find(':selected').data('slide');
goToByScroll(dataslide);
});
Ok, and now we need to ensure that the listbox changes its default value as the user performs the scrolling. We will leverage some bits of the code you posted. Something like this will be enough:
slide.waypoint(function (d, e) {
var dataslide = c(this).attr("data-slide");
$('select').prop('selectedIndex', parseInt(dataslide)-1);
});
AS a word of caution, the code above assumes that all aslides have a numeric data-slide value that goes from 1 to n and each listbox index refer to a matching slide with the same index in the page, plus 1, being its sorting order the same as the dataslide it represents.

Related

AngularJS - div still shows even without condition

Ok, I know that title could use some work, but I'm not sure how else to put it.
Here's the setup.
I have a (potentially) massive table that gets generated via an ng-repeat. All the rows need to be editable but, when the dataset is so large, all those bindings slow things to a crawl. I could literally be waiting upwards of 20 seconds for large sets to load!
We noticed that dumping the data in a read-only state significantly decreased the load time. So, we came up with the idea of loading it read-only, but, when the table row was clicked, it became editable. This is accomplished like so. I have two cells output. editableRow is initially false. When the row is clicked, editableRow becomes true. The idea being that, when editableRow becomes true, I see the other cell.
(proprietary code obfuscated)
<TABLE-CELL class="value-col" ng-if="readtime.editableRow === true">
<input type="text"
name="readingTime"
ng-model="<data model>"
ng-disabled="<param>"
ng-change="<function>"
ng-class="<classes>"
/>
</TABLE-CELL>
<TABLE-CELL class="value-col" ng-if="readtime.editableRow === false">
<input type="text"
placeholder="{{<data model>}}"
ng-class="<classes>"
/>
</TABLE-CELL>
The problem is, on the click, for a tiny fraction of a second both cells are visible. It really is only visible on the first click. Subsequent clicks still do it, but it goes so fast that the human eye can't catch it. I know it's there since I slowed everything down with a breakpoint on the mouse click. This also revealed that this happens as the value turns true - turning on the first cell, but the second one doesn't disappear in the same moment. So, it causes a "flicker" of sorts. This seems to happen outside my actual code, inside the jQuery, so I'm not sure how to short circuit it.
I've tried playing with using ng-show/hide instead, which worked a little bit, but also totally negated the time-saving aspect, since it actually renders everything, and it took a long time. I've also tried ng-cloak with no effect whatsoever.
The breakpoint that it keeps stopping on (when I told it to stop on event listeners to do with the mouse click) is the following code in jquery.js:
if ( !(eventHandle = elemData.handle) ) {
eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
jQuery.event.dispatch.apply( elem, arguments ) : undefined;
};
}
It hits that line about 4 times, and, on the last one, both cells are visible. Then, the second one disappears.
I'm out of ideas and would appreciate any thoughts on this.
I finally found an answer that works!
On this page: disable nganimate for some elements the answer right BELOW the accepted answer is what finally worked!
To disable ng-animate for certain elements, using a CSS class, which follows Angular animate paradigm, you can configure ng-animate to test the class using regex.
Config
var myApp = angular.module("MyApp", ["ngAnimate"]);
myApp.config(function($animateProvider) {
$animateProvider.classNameFilter(/^(?:(?!ng-animate-disabled).)*$/);
})
Usage
Simply add the ng-animate-disabled class to any elements you want to be ignored by ng-animate.

Bind value to dynamic dropdown, from localStorage - AngularJs

I have this project, with VB for backend and AngularJS for the frontend. 1 of the issues i am tasked to fix is a dropdown that doesn't keep it's values after i change page and then go back to said page.
In more detail:
i have a list coming from the backend - VB, with all the data i need.
i have a view that has a 4 dropdowns to apply filters to the page .
i apply a filter or a combination of filters to see only the desired applications.
i click on an application and therefore i am redirected to the page of said application.
i do all i have to do there and so i click the browser back button to go to the list of all the applications.
the filters are lost and i need to still have them active.
List item
<select id="issue1"
ng-model="RecordStatus"
ng-change="RecordStatusSelection(RecordStatus.ID_RecordStatus)"
ng-options="RecordStatus.RecordStatusDesc for RecordStatus in MyDiversionESDList
| unique:'RecordStatusDesc'
| orderBy:'+RecordStatusDesc'">
<option id="issue1" value="">-- Όλες --</option>
</select>
what i have done so far:
i bind the value of each dropdown (each filter to be exact) in localStorage
the localStorage values change along with the dropdowns
What i need is to have the values of localStorage apply to said dropdown, so that each filter can still be applied when i go back to this page.
More code to help you, help me:
1. js code, inside the controller - where i get the filter and save it in localStorage
$scope.RecordStatusSelection = function (recordStatus) {
$scope.filterScope.ID_RecordStatus = recordStatus;
localStorage.setItem('sessionIdRecordStatus', recordStatus);
return $scope.applyMasterFilter()
}
2. js code, where i apply the filters
$scope.applyMasterFilter = function (temp) {
$scope.temp = localStorage.getItem('sessionIdRecordStatus');
$scope.filteredDiversionESD = $filter("filter")($scope.MyDiversionESDList, $scope.filterScope)
$scope.filteredDiversionESD = $filter("filter")($scope.filteredDiversionESD,
$scope.searchKeywordsText)
return $scope.onFilterChange()
}
In case anyone else has the same issue:
I used sessionsStorage. Session instead of Local because i want it to be at the default values each time the website starts.
$scope.RecordStatusSelection = function (recordStatus) {
sessionStorage.setItem('sessionIdRecordStatus', recordStatus);
$scope.filterScope.ID_RecordStatus = sessionStorage.sessionIdRecordStatus;
return $scope.applyMasterFilter()
}
$scope.applyMasterFilter = function (temp) {
$scope.filterScope.ID_RecordStatus = sessionStorage.sessionIdRecordStatus;
$scope.filteredDiversionESD = $filter("filter")($scope.MyDiversionESDList, $scope.filterScope)
$scope.filteredDiversionESD = $filter("filter")($scope.filteredDiversionESD,
$scope.searchKeywordsText)
return $scope.onFilterChange()
}
It works well, but not too well. The value/option is applied but not shown, i get an empty box instead.
I will edit this answer if i find the full solution.

Angular ng-repeat with Search not working when search is empty

I have the following:
<div ng-repeat="foo in foos | filter:search | orderBy:'fooName'">
<input type="checkbox" id="cb-{{$index}}" ng-click="diseaseCheckboxClick($index)"/>
<input type="hidden" id="foo-{{$index}}" value="{{foo.id}}"/>
<label id="label-{{$index}}">{{foo.fooName}}</label>
</div>
The collection of 'foos' comes from a ReST call.
A person has a collection of 'foos', and I have a function that loops over each 'foos' collection, and the job of the function is to checkmark the 'foo' or not. If the person has that particular 'foo', checkmark it.
I use the a hidden text field to hold the fooIds, and I use it for comparison.
for (var i = 0; i < $scope.person.foos.length; i++) {
var outerFooId = $scope.person.foos[i].id;
for (var j = 0; j < $scope.foos.length; j++) {
var fooElem= '#foo-' + j;
var fooIdValue = $(fooElem).val();
if (outerFooId === fooIdValue) {
var cbId= '#cb-' + j;
$(cbId).attr('checked', true);
break;
}
}
}
The only problem I have is that when I enter a search item that brings back zero results (and that works), but then when I backspace back and remove the search items that brought back no results, the function that is used to checkmark the checkboxes does not work, it is due to the call '$(fooElem).val();' in the function returns undefined.
I see the list in the page, and when i view source i see all of the fields, including the hidden text field that holds the fooId, so I do not know why the function does not 'see' it.
Note that this only occurs when I enter a search that brings back no results, then backspace over to clear out the search field.
The search and marking the checkboxes work otherwise.
Any idea why this is happening, or how I can make the function 'see' the hidden text field. I'll note that I also tried to use the 'label' element, but same result, the text of the label is undefined.
This will not completely solve your problem, but I have to point out that you are making the classic mistake of mixing methodologies. In Angular, you should never, EVER have any code that manipulates the DOM outside of a directive, and even then it is rarely necessary.
There are two classic clues here - you are using $() (jquery), and you are using HTML DOM id attributes. The only real use for id's in Angular is to associate labels with input elements (which you are not doing here), and even then in most cases you can get away with encasing the input inside the label instead of using the "label for" syntax.
Having said all of that, and without seeing the rest of your code, here is how you "angularize" what you are doing:
I am going to make a few assumptions (that should probably be answered by your question):
1) foos is a list of all foos. Each foo has a unique id and name.
2) a person can have some or all foos.
3) The purpose of your code is to allow someone to see which foos they have, and filter the list by name.
So first, the model:
To make things fast (avoid looping when checking each foo, foos should be indexed by id. To when you load them from your for a person, you should create a map by id:
var fooMap = {};
foreach(var i in person.foos) {
fooMap[person.foos[i].id] = person.foos[i];
}
Note that this could be simplified if person.foos is already a map by id!
You also need a few methods in your controller:
$scope.hasFoo(foo) {
return fooMap[foo.id];
}
And your template becomes:
<div ng-repeat="foo in foos | filter:search | orderBy:'fooName'">
<label>{{foo.fooName}}<input type="checkbox" ng-click="diseaseCheckboxClick(foo)" ng-checked="hasFoo(foo)"/></label>
</div>
Note no hidden input, no id's - just a template that is driven by the state of your $scope.
This will solve the immediate problem (losing foos after a search).
The last part of the puzzle is implementing your click function. Without knowing more about your actual implementation, here is the general idea (you'll have to figure the details out yourself).
$scope.diseaseCheckboxClick = function(foo) {
if(fooMap[foo.id]) {
//remove the foo from $scope.person.foos
// and update fooMap
delete fooMap[foo.id];
}
else {
//add the foo to $scope.person.foos and update fooMap
$scope.person.foos.push(foo);
fooMap[foo.id] = foo;
}
}
Hopefully this points you in the right direction. I'm inferring a lot, so I'm sure I've got a few things wrong, but the key problem you have right now is mixing jQuery with Angular.

ng-options creates an empty option at the end when listbox group heading is clicked

I am stuck on this particular issue with ng-options. I am creating a listbox with option grouping:
<select ng-model="selTemplates" size="3" style="width: 150px"
ng-options="template.Name group by template.Type for template in userTemplates">
</select>
When I click on a group heading (Type1 or Type2), Chrome creates an empty option at the end and marks it selected. I believe it has something to do with the selection because it may not find anything 'selected' when a header is clicked, but an empty value at the bottom is not desired.
Please see the fiddle here.How can i fix it?
(The code works fine in IE9, although not sure why the fiddle doesn't)
ng-options adds empty option if case if value currently bound by ng-model doesn't exist in list of options. This prevents from overwriting value due bounding to empty select (this is an often problem in for example knockoutjs).
Clicking option group clears selection and empty option added.
You can see it if add debug <div>{{selTemplates}}</div> below select list.
Also even static select with size or multiple attribute specified clears its selection on clicking option. If size is omitted (for regular dropdown) clicking optgroup doesn't clears selected value.
I'm not sure if this browser inconsistence or expected behavior (if you said it works in IE) but consider replacing select with custom HTML emulates list selection.
Looks like inconsistent browser implementation is the reason. On clicking option header, Chrome clears out the selection whereas IE doesn't, that's why Chrome inserts a new empty row at the bottom.
As a workaround, I am saving last selected value in a variable, and in case user clicks on header (which will make selection null), I am restoring the last selection. See fiddle. Not exactly pretty, but gets the work done.
$scope.checkSelection = function() {
if ($scope.selTemplates == null) {
$scope.selTemplates = last;
}
else {
last = $scope.selTemplates;
}
}
Add ng-init="selTemplates=userTemplates[0]" in your <select>
You can remove "$scope.selTemplates = ***" in your controller

Is there a better way to have dynamic text appear next to a combobox?

I have a combobox, and based on the current selection, I would like dynamic text to appear beside the combobox.
My current solution works, but seems kludgy and fragile. It may not work at all depending on where the combobox appears in the DOM.
Here is the crux of my current solution (called when dropdown changes):
var child = owner.el.first().next().first().first().first().next().first();
if (child.dom.childNodes.length == 3) {
child.createChild({
tag: 'span',
html: c + Ext.id()
});
} else {
child.last().replaceWith({
tag: 'span',
html: c + Ext.id()
});
}
I'm mostly concerned about the first line...this can't be a good way of finding an insertion point.
Here is a pic of the combo box with the dynamic text appearing beside:
And here is what I looked at to find where I wanted to insert the text:
Can someone suggest a better way of achieving this effect? Thanks.
Have the span in the page already and grab it by its id.
Ext.get('combo-suffix').insertHTML(theText);
Or, grab the combo box element by its id and get/add its sibling.
Will it always be in a div called "ext-gen82"?
If so, why not use the jquery find method?
$("#ext-gen82").find("ext-gen107");
Alternatively you could give them their own class to help you find them as well:
$(".parentClass").find(".spanElement");
You could also use the children method:
$("#ext-gen82").children("span");
#OrangeDog pointed me the right direction, but I'll post a more detailed answer here for completeness/future reference.
var inserted = false; // need to set this up initially
...
var pos = Ext.getCmp('combo-element-id').el.next('.x-form-trigger');
if (inserted) {
pos.next().update(c + Ext.id());
} else {
inserted = true;
pos.insertSibling({
tag: 'span',
html: c + Ext.id()
}, 'after');
}

Resources