Sort objects by property AngularJS - angularjs

I have a collection of avatars with a property 'orderNumber' in model. I need my collection of avatars to sort by 'orderNumber' field. Each object has it's orderNumber and if you change orderNumber of Object in robomongo for example, objects swaps due to its 'orderNumber' number.
Here is my model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var CollectionSchema = new Schema({
name: {
type: String,
required: 'Name is required!'
},
description: {
type: String
},
orderNumber:{
type: Number
},
defaultAvatar: [{
type: Schema.Types.ObjectId,
ref: 'Part'
}],
designer_id: {
type: Schema.Types.ObjectId,
ref: 'Designer'
},
pipeline: [{
name: {
type: String,
required: 'Pipeline step name is required!'
},
zoom: Boolean,
templates: [{
name: {
type: String,
required: 'Template name is required!'
},
parts: [{
type: Schema.Types.ObjectId,
ref: 'Part'
}]
}]
}]
});
module.exports = mongoose.model('Collection', CollectionSchema);>
Here is my controller
(function () {
'use strict';
angular
.module( 'mainApp' )
.controller( 'simpleACController', simpleACController );
function simpleACController( $scope, $location, $compile, $localStorage, CanvasRendererFactory, WrapUnwrapFactory,
PremadeAvatarManager, PartsFactory, AvatarConstructorFactory, UserAvatarsFactory,
JqueryRenderFactory, UserFactory ) {
var vm = this; // ViewModel, you are free of controller's name in html
var canvas = new fabric.StaticCanvas( '' );
vm.showPreviousButton = false;
vm.showNextButton = true;
var savedAvatarMiniatures = [];
var savedPipelineNumber;
// var canvas = new fabric.StaticCanvas( 'simpleAvatarCanvas' );
var pipelineNumber; // -1
var previousPipeline;
var selectedType;
var selectedIndex = 0;
var previousIndex = 0;
var miniatureCarousel;
var avatarCarousel;
var transitionInProgress = false;
vm.avatars = [];
var initialAvatars = [];
var pipelineNames = {};
var pipelineZooms;
vm.select = function ( index ) {
savedAvatarMiniatures = vm.avatars;
selectedIndex = index;
if (pipelineNumber == -1) {
selectedType = index;
}
var wasSelected = vm.avatars[index].selected;
for (var i = 0; i < vm.avatars.length; i++) {
vm.avatars[i].selected = false;
}
vm.avatars[index].selected = !wasSelected;
if (pipelineNumber == -1) {
vm.avatarName = vm.avatars[index].name;
}
vm.showPreviousButton = ( index != 0 );
vm.showNextButton = ( index != (vm.avatars.length - 1) );
};
vm.selectNext = function () {
previousIndex = selectedIndex;
if (selectedIndex < vm.avatars.length - 1) {
changeMiniatureCarousel( ++selectedIndex );
}
};
vm.selectPrevious = function () {
previousIndex = selectedIndex;
if (selectedIndex > 0) {
changeMiniatureCarousel( --selectedIndex );
}
};
vm.onMiniatureClick = function ( index ) {
if (!transitionInProgress) {
vm.select( index );
}
};
vm.prevPipeLine = function () {
var avatar = getSelectedAvatar();
if (avatar != null) {
if (pipelineNumber < getPipelineCount( avatar )) {
previousPipeline = pipelineNumber;
pipelineNumber--;
updatePipeline();
} else {
pipelineNumber--;
}
vm.switchCarousel( true );
}
updateText();
};
vm.nextPipeLine = function () {
if (getSelectedAvatar() != null) {
previousPipeline = pipelineNumber;
pipelineNumber++;
updatePipeline();
}
updateText();
};
vm.showCarousel = true;
vm.switchCarousel = function ( flag ) {
vm.showCarousel = flag;
};
vm.saveAvatar = function () {
if (!UserFactory.IsLoggedIn()) {
$localStorage.anonymousAvatar = getSelectedAvatar();
UserFactory.showLoginModal( function () {
save();
}, function ( err ) {
console.log( 'saveAvatar Error' );
console.log( err );
} );
} else {
save();
}
function save() {
var avatar = getSelectedAvatar();
var partIds = WrapUnwrapFactory.unwrapPartIds( avatar );
UserAvatarsFactory.saveAvatar( avatar.orderNumber, vm.avatarName, partIds, function () {
$location.path( '/avatarmanager' );
$scope.$apply();
} );
}
};
vm.toFullAC = function () {
if (!UserFactory.IsLoggedIn()) {
UserFactory.showLoginModal( function () {
toFullAC( getSelectedAvatar() );
}, function ( err ) {
console.log( 'toFullAC Error' );
console.log( err );
} );
} else {
toFullAC( getSelectedAvatar() );
}
};
function changeMiniatureCarousel( index ) {
refresh( index );
miniatureCarousel.trigger( 'to.owl.carousel', [index] );
}
function selectMiniatureCarousel() {
var index = ( pipelineNumber == -1 && selectedType != undefined ) ? selectedType : 0;
changeMiniatureCarousel( index )
}
function getSelectedAvatar() {
var avatar = null;
if (vm.avatars.length > 0) {
for (var i = 0; i < vm.avatars.length; i++) {
if (vm.avatars[i].selected == true) {
avatar = vm.avatars[i];
}
}
}
return avatar;
}
function updatePipeline() {
var avatar = getSelectedAvatar();
if (avatar) {
if (pipelineNumber < getPipelineCount( avatar )) {
updateMiniatures( avatar ).then( function () {
return true;
} );
} else {
if (!UserFactory.IsLoggedIn()) {
updateViewModel();
vm.switchCarousel( false );
} else {
toFullAC( avatar );
}
}
}
return false;
}
function updateText() {
var avatar = getSelectedAvatar();
if (pipelineNames.length != 0) {
var names = ['type'];
for (var i = 1; i < pipelineNames[avatar.orderNumber].length; i++) {
names.push( pipelineNames[avatar.orderNumber][i] );
}
if (pipelineNumber > -2) {
vm.heading = 'Select avatar ' + names[pipelineNumber + 1];
}
if (pipelineNumber >= getPipelineCount( avatar )) {
vm.heading = "Your avatar is ready! Save?"
}
}
}
function getPipelineCount( avatar ) {
return PremadeAvatarManager.getPipelineCount( avatar );
}
function updateCarousels() {
renderAvatars();
renderMiniatures();
bindCarousels();
}
function renderMiniatures() {
var slideCount = 6;
slideCount = ( vm.avatars.length < slideCount ) ? vm.avatars.length : slideCount;
var settings = {
array: vm.avatars,
imageProperty: 'premade',
type: 'canvas',
width: 150,
height: 100,
vmArray: 'simpleAC.avatars',
oldCarousel: '#simpleACcarousel',
carouselRoot: '#miniatures-carousel-root',
containerClass: "as-slider",
containerID: "simpleACcarousel",
divClick: ' ng-click="simpleAC.onMiniatureClick',
slideCount: slideCount,
centerMode: false,
needsText: true,
selectable: true
};
var divNroot = JqueryRenderFactory.render( settings, $scope, $compile );
miniatureCarousel = divNroot.div;
//divNroot.root.append( miniatureCarousel );
$compile( divNroot.root )( $scope );
CanvasRendererFactory.renderAvatarsToCanvasesInCarousel( vm.avatars, miniatureCarousel );
miniatureCarousel.owlCarousel( {
responsive: {
0: {
items: 5,
},
1439: {
items: 7,
}
},
animateIn: 'fadeIn',
animateOut: 'fadeOut',
center: true,
loop: false,
margin: 10,
mouseDrag: false,
touchDrag: false,
nav: false
} );
}
function renderAvatars() {
var slideCount = 3;
slideCount = ( vm.avatars.length - 1 < slideCount ) ? 1 : slideCount;
var settings = {
array: vm.avatars,
imageProperty: 'premade',
type: 'canvas',
width: 480,
height: 320,
vmArray: 'simpleAC.avatars',
oldCarousel: '#simpleACavatarCarousel',
carouselRoot: '#avatars-carousel-root',
containerClass: "ag-slider",
containerID: "simpleACavatarCarousel",
divClick: ' ',
slideCount: slideCount,
centerMode: true,
needsText: false,
selectable: false
};
var divNroot = JqueryRenderFactory.render( settings, $scope, $compile );
avatarCarousel = divNroot.div;
//divNroot.root.append( avatarCarousel );
$compile( divNroot.root )( $scope );
CanvasRendererFactory.renderAvatarsToCanvasesInCarousel( vm.avatars, avatarCarousel );
avatarCarousel.owlCarousel( {
animateIn: 'fadeIn',
animateOut: 'fadeOut',
items: 5,
center: true,
loop: false,
margin: 10,
mouseDrag: false,
touchDrag: false,
nav: false
} );
var items = $( '.owl-item' );
items.removeClass( 'medium' );
items.eq( 1 ).addClass( 'medium' );
avatarCarousel.on( 'translate.owl.carousel', function ( e ) {
var index = e.item.index;
var items = $( '.owl-item' );
items.removeClass( 'medium' );
items.eq( index - 1 ).addClass( 'medium' );
items.eq( index + 1 ).addClass( 'medium' );
} );
}
function renderCanvasesInCarousel( carousel ) {
var canvasArray = carousel.find( "canvas" );
for (var i = 0; i < vm.avatars.length; i++) {
var canvas = new fabric.StaticCanvas( canvasArray[i] );
canvasArray[i].removeAttribute( 'style' );
WrapUnwrapFactory.unwrapAvatar( vm.avatars[i], {x: canvas.width, y: canvas.height},
function ( canvas ) {
return function ( array ) {
CanvasRendererFactory.drawAvatar( canvas, array );
}
}( canvas )
);
}
}
function bindCarousels() {
var changing = false;
var changed;
var duration = 300;
avatarCarousel.on( 'changed.owl.carousel', function ( e ) {
if (!changing) {
changing = true;
miniatureCarousel.trigger( 'to.owl.carousel', [e.item.index, 0] );
changing = false;
}
} );
miniatureCarousel.on( 'click', '.owl-item', function () {
if (!transitionInProgress) {
var index = $( this ).index();
avatarCarousel.trigger( 'to.owl.carousel', [index, 0] );
}
} );
miniatureCarousel.on( 'translate.owl.carousel', function ( e ) {
transitionInProgress = true;
} );
miniatureCarousel.on( 'translated.owl.carousel', function ( e ) {
transitionInProgress = false;
} );
miniatureCarousel.on( 'changed.owl.carousel', function ( e ) {
if (!changing) {
changing = true;
avatarCarousel.trigger( 'to.owl.carousel', [e.item.index, 0] );
refresh( e.item.index );
if (!$scope.$$phase) {
$scope.$apply();
}
changing = false;
}
} );
}
function initpipelineNames() {
vm.avatars.forEach(function(avatar) {
var resultArray = [];
PremadeAvatarManager.getPipeline(avatar).forEach(function(pipeline) {
resultArray.push(pipeline.name);
});
pipelineNames[avatar.orderNumber] = resultArray;
});
AvatarConstructorFactory.SimpleACpipelineNames( pipelineNames );
}
function updateViewModel() {
vm.backButtonHidden = ( pipelineNumber == -1 );
}
function updateMiniatures( avatar ) {
return new Promise( function ( resolve ) {
PremadeAvatarManager.getAvatarArray( avatar, pipelineNumber ).then( function ( collection ) {
vm.avatars = collection;
console.log(avatars);
if (pipelineNumber == -1) {
initialAvatars = collection;
}
// var index = ( pipelineNumber == -1 && selectedType != undefined ) ? selectedType : 0;
updateViewModel();
updateAvatarConstructorFactory();
updateCarousels();
selectMiniatureCarousel();
switchZoom();
if (!$scope.$$phase) {
$scope.$apply();
}
resolve()
} );
} );
//return (vm.avatars != undefined);
}
function changeLocationAfterLoaded( avatar ) {
AvatarConstructorFactory.SelectedAvatarToFullAC( avatar );
$location.path( '/fullac' );
if (!$scope.$$phase) {
$scope.$apply();
}
}
function toFullAC( avatar ) {
var defaultTypes = PartsFactory.getDefaultPartTypes( avatar.orderNumber );
var avatarTypes = WrapUnwrapFactory.unwrapTypes( avatar );
var filtered = _.filter( defaultTypes, function ( type ) {
return avatarTypes.indexOf( type ) >= 0; // contains
} );
var typesStack = PartsFactory.getPartsByTypeArray( avatar.orderNumber, filtered );
AvatarConstructorFactory.TypesStack( typesStack );
changeLocationAfterLoaded( avatar );
}
function refresh( index ) {
index = ( index == undefined ) ? 0 : index;
if (vm.avatars[index].selected) {
vm.select( index );
}
vm.select( index );
}
function updateAvatarConstructorFactory() {
AvatarConstructorFactory.SimpleACavatarMiniatures( vm.avatars );
AvatarConstructorFactory.SimpleACpipelineNumber( pipelineNumber );
}
function switchZoom() {
var items = $( '.avatar-gallery .owl-item' );
if (pipelineNumber > -1 && pipelineZooms == undefined) {
var avatar = getSelectedAvatar();
var collection = PartsFactory.findCollection( avatar.orderNumber);
pipelineZooms = [];
collection.pipeline.forEach( function ( pipeline ) {
if (pipeline.zoom) {
pipelineZooms.push( true );
} else {
pipelineZooms.push( false );
}
} );
setZoom();
} else if (pipelineNumber > -1) {
setZoom();
}
function setZoom() {
if (pipelineZooms[pipelineNumber + 1]) {
items.addClass( 'zoom' );
} else {
items.removeClass( 'zoom' );
}
}
}
function activate() {
PartsFactory.registerCollectionObserverCallback( internalActivate );
if (PartsFactory.areCollectionsInitialized()) {
internalActivate();
}
function internalActivate() {
if (!AvatarConstructorFactory.isInit()) {
pipelineNumber = -1;
updateMiniatures().then( function () {
initpipelineNames();
updateText();
if (!$scope.$$phase) {
$scope.$apply();
}
vm.selectNext()
} )
} else {
updateViewModel();
pipelineNumber = AvatarConstructorFactory.SimpleACpipelineNumber();
vm.avatars = AvatarConstructorFactory.SimpleACavatarMiniatures();
pipelineNames = AvatarConstructorFactory.SimpleACpipelineNames();
updateCarousels();
selectMiniatureCarousel();
switchZoom();
updateText();
refresh();
if (!$scope.$$phase) {
$scope.$apply();
}
vm.selectNext()
}
}
}
activate();
}
})();
and the view
<div ng-controller="simpleACController as simpleAC" class="inner-bg clearfix">
<div class="inner avatar-generator">
<div class="character-bg">
<div class="layer-one"></div>
<div class="layer-two"></div>
</div>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="avatar-gallery">
<div class="controls">
<div class="add-name">
<form action="">
<input type="text"
class="cell"
ng-hide="simpleAC.showCarousel"
ng-model="simpleAC.avatarName">
</form>
</div>
</div>
<div class="ag-controls">
<i class="ag-prev" ng-show="simpleAC.showCarousel && simpleAC.showPreviousButton"
ng-click="simpleAC.selectPrevious()">prev</i>
<i class="ag-next" ng-show="simpleAC.showCarousel && simpleAC.showNextButton"
ng-click="simpleAC.selectNext()">next</i>
</div>
<div id="avatars-carousel-root"></div>
</div>
</div>
</div>
<div class="avatar-details">
<div class="container">
<div class="title">
<span class="back button"
ng-hide="simpleAC.backButtonHidden"
ng-click="simpleAC.prevPipeLine()">back</span>
<h2 ng-bind="simpleAC.heading">Select avatar type</h2>
<span class="next button"
ng-show="simpleAC.showCarousel"
ng-click="simpleAC.nextPipeLine()">next</span>
</div>
<div class="avatar-styles">
<div ng-show="simpleAC.showCarousel">
<div class="as-controls">
<i class="as-prev" ng-show="simpleAC.showPreviousButton"
ng-click="simpleAC.selectPrevious()">prev</i>
<i class="as-next" ng-show="simpleAC.showNextButton" ng-click="simpleAC.selectNext()">next</i>
</div>
<div id="miniatures-carousel-root">
</div>
</div>
<div ng-show="!simpleAC.showCarousel">
<div class="done-controls">
<a class="btn fakelink" ng-click="simpleAC.toFullAC()">Edit details</a>
<a class="btn button-blue fakelink" ng-click="simpleAC.saveAvatar()">Save</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

You can sort your collection with the angular's filter "orderBy".
Ref : http://justinklemm.com/angularjs-filter-ordering-objects-ngrepeat/
If you want use this filter in javascript and not on ng-repeat
$filter('orderBy')(array, expression, reverse)
https://docs.angularjs.org/api/ng/filter/orderBy

Related

React-share. Throws error TypeError: Super expression must either be null or a function, not undefined when trying to use it in require

I am new in ReactJs and trying to learn it. I installed a package of react-share. Since i am trying to edit someone else's code i am not able to import the package due to webpack I believe. Every time i try to import a package I receive an error saying the import should always be on top of the script. I tried using require and I get this error in Console
TypeError: Super expression must either be null or a function, not undefined
My code looks like this:
"use strict";
require('./../../../assets/styles/components/thread.less');
var reactShare = require('react-share');
var React = require('react');
var ReactDOM = require('react-dom');
var Fluxxor = require('fluxxor');
var _ = require("lodash");
var FluxMixin = Fluxxor.FluxMixin(React);
var StoreWatchMixin = Fluxxor.StoreWatchMixin;
var routerShape = require('react-router').routerShape;
var MicroAudioViews = require('./../../constants/MicroAudioViews');
var AudioModes = require("./../../constants/AudioModes");
var i18n = require("i18next-client");
//components
var AudioVisualizer = require('../elements/AudioVisualizer');
var ReviewOverlay = require('../elements/ReviewOverlay');
var ReviewShare = require('../elements/ReviewShare');
var Menu = require('../elements/Menu');
I have to use react-share's
<FacebookShareButton url={shareLink} quote={title} className="social-media-icon">
<FacebookIcon size={32} round />
</FacebookShareButton>`
Component to share the shareLink on facebook.
Here the full code.
/*import {
FacebookShareButton,
GooglePlusShareButton,
TwitterShareButton,
WhatsappShareButton,
FacebookIcon,
TwitterIcon,
WhatsappIcon
} from 'react-share';*/
"use strict";
require('./../../../assets/styles/components/thread.less');
var reactShare = require('react-share');
var React = require('react');
var ReactDOM = require('react-dom');
var Fluxxor = require('fluxxor');
var _ = require("lodash");
var FluxMixin = Fluxxor.FluxMixin(React);
var StoreWatchMixin = Fluxxor.StoreWatchMixin;
var routerShape = require('react-router').routerShape;
var MicroAudioViews = require('./../../constants/MicroAudioViews');
var AudioModes = require("./../../constants/AudioModes");
var i18n = require("i18next-client");
//components
var AudioVisualizer = require('../elements/AudioVisualizer');
var ReviewOverlay = require('../elements/ReviewOverlay');
var ReviewShare = require('../elements/ReviewShare');
var Menu = require('../elements/Menu');
var Review = React.createClass({
mixins:[
FluxMixin,
StoreWatchMixin("ThreadStore", "RecordStore", "ReviewStore", "ApplicationStore", "SyncStore", "DemoStore", "ShareStore")
],
contextTypes: {
router: routerShape.isRequired
},
/* react interface*/
getInitialState: function() {
var selectedThreads = [];
var shareType = 'thread';
if(this.props.location.state && this.props.location.state.type == "thread") {
selectedThreads.push(this.props.location.state.threadId);
} else if(this.props.location.state && this.props.location.state.type == "share") {
shareType = 'facebook';
} else if (this.props.location.state && this.props.location.state.type == 'sharereply') {
shareType = 'sharereply';
}
return {
threadUserId: this.props.params.id,
activeShareType: shareType,
selectedThreads: selectedThreads
};
},
getStateFromFlux: function() {
var flux = this.getFlux();
var recordStoreState = flux.store('RecordStore').getState();
var threadStoreState = flux.store('ThreadStore').getState();
var appStoreState = flux.store('ApplicationStore').getState();
var reviewStoreState = flux.store('ReviewStore').getState();
var shareStoreState = flux.store('ShareStore').getState();
var demoState = flux.store('DemoStore').getState();
var activeRecord = recordStoreState.activeRecord || null;
var activeThread = threadStoreState.activeThread;
var activeRecordUser = null;
var authenticatedUser = appStoreState.demoMode? demoState.user : appStoreState.user;
var state = {
demoMode: appStoreState.demoMode,
playing: recordStoreState.playing,
recording: recordStoreState.recording,
activeThread: activeThread,
threads: threadStoreState.threads,
authenticatedUser: authenticatedUser,
activeRecord: activeRecord,
activeShareUser: shareStoreState.user,
shareId: shareStoreState.shareId
};
return state;
},
render: function() {
var threadClass = "thread";
var fbClass = "facebook";
var explanationText, usageContent;
var finishButtonClass = 'finish-button';
if(this.state.activeShareType == "thread") {
threadClass += ' active';
explanationText = i18n.t('content:review.reviewDoneExpl', {
count: this.state.selectedThreads.length,
context: this.state.selectedThreads.length == 0 ? 'doselect' : undefined
});
finishButtonClass += this.state.selectedThreads.length == 0 ? ' inactive' : '';
var threadCards = [];
var self = this;
_.each(this.state.threads, function(thread){
var threadUser = thread.user;
var threadUserPicture = threadUser.pictures[0].source;
var userName = threadUser.firstName + ' ' + threadUser.lastName;
var styleProps = {
backgroundImage : threadUserPicture ? 'url(' + threadUserPicture + ')': 'none'
};
var cls = "thread card" + (self.state.selectedThreads.indexOf(thread.id) != -1? " selected" : "");
threadCards.push(<div key={thread.id} className={cls} onClick={self.onThreadCardSelected} data-thread-id={thread.id}>
<div className='pic' style={styleProps}></div>
<div className='name'>{userName}</div>
<div className='checked micro-audio-icon-check'></div>
</div>);
});
//if thread cards array is null then we are displaying the required text
if(threadCards.length==0){
var text= "Du hast noch keine Freunde in audiyoh hinzugefugt (gehe dafur zur Suche).";
//displaying the content
usageContent = (
<div className="usage-target-container">
<p className="chat-text">{text} <br/>Uber <img className="share-icon" src={require('./../../../assets/images/share-active.png')} /> Teilen kannst du deine Aufnahme in aderen Kanale teilen.</p>
</div>);
//displaying the button
var finishContainer = <div className="finish-container">
<div className={finishButtonClass} >Fertige</div>
<div className="finish-text"><p className="chat-underbtn-text">Mindestens <b> ein Gesprach <br/> wahlen,</b> dem die Aufnahme <br/> hinzugefugt werden soll</p></div>
</div>;
}else{
usageContent = (
<div className="usage-target-container">
{threadCards}
</div>);
}
} else {
fbClass += ' active';
finishButtonClass += ' facebook';
explanationText = i18n.t('content:review.facebookExplanation');
//displaying the input box with the link and copy button
console.log("THe shareStoreState is " + this.state.shareId);
//the shareId is generate asynchroneously, so this.state.shareId can be null
if(typeof this.state.shareId === "string") {
//the link can be created like this:
var shareLink = window.location.origin + '/shared/' + this.state.shareId;
}
var usageContent = (
<div className="usage-target-container">
<div className="socialLinkContainer">
<p> Link zum Teilen </p>
<input className="copylink" type="text" value={shareLink} id="shareLink" /><br/>
<input className="copybtn" type="button" onClick={this.copytoclipboard} value="Link kopieren" />
</div>
</div>);
var finishContainer = <div className="finish-container">
<div className="social-media">
/*<img className="social-media-icon" src={require('./../../../assets/images/facebook.png')} />*/
<FacebookShareButton
url={shareLink}
quote={title}
className="social-media-icon">
<FacebookIcon
size={32}
round />
</FacebookShareButton>
<img className="social-media-icon" src={require('./../../../assets/images/whatsapp.png')} />
<img className="social-media-icon" src={require('./../../../assets/images/twitter.png')} />
<img className="social-media-icon" src={require('./../../../assets/images/instagram.png')} />
</div>
</div>;
}
var targetSwitchElements = [
<div title={i18n.t('content:review.sharethread')}
key="thread"
className={threadClass}
onClick={this.activateThreadShareType}><span>audiyoh-chat</span></div>,<br/>,
<div title={i18n.t('content:review.sharefb')}
key="facebook"
className={fbClass}
onClick={this.activateFBShareType}><span>Teilen</span></div>
];
//we either want to save a profile record a share response, so we dont need the fb/thread switch and thread cards
if(this.props.location.state && ["profile", "sharereply"].indexOf(this.props.location.state.type) != -1) {
var buttonText = i18n.t('content:review.profile');
if(this.props.location.state.type == "sharereply"){
buttonText = i18n.t('content:review.share', {name: this.state.activeShareUser.firstName});
}
targetSwitchElements = <div className="profile-record" onClick={this.onFinishRecord}>{buttonText}</div>;
usageContent = null;
finishContainer = null;
}
return (
<div className="ma-reviewing">
<div className="review-controls">
<div className="row">
<div className="col-3">
<a title={i18n.t('content:review.delete')} className="delete" onClick={this.deleteRecording}></a>
<a title={i18n.t('content:review.redo')} className="record" onClick={this.onRecordButtonClick}></a>
</div>
<div className="col-6">
<div className="review-container">
<ReviewOverlay
activeRecordUser={this.state.authenticatedUser}
record={this.state.activeRecord}
/>
</div>
</div>
{finishContainer}
<div className="col-3">
<div className="target-switch">
<p>Weiter mit der Aufnahme</p>
{targetSwitchElements}
</div>
</div>
</div>
</div>
<div className="upper" ref="upper">
<Menu location={this.props.location} />
<div className="menu">
</div>
</div>
<div className="upperguard" ref="upperguard"></div>
<div className="lower" ref="lower">
<div className="sizing-wrapper">
{usageContent}
</div>
</div>
</div>
);
},
deleteRecording: function(e) {
e.preventDefault();
if(this.props.location && this.props.location.state.userId) {
this.context.router.push({
pathname: "/thread/" + this.props.location.state.userId,
state: this.props.location.state
});
}
else {
this.context.router.push({
pathname: "/profile",
state: this.props.location.state
});
}
},
onRecordButtonClick: function(e) {
e.preventDefault();
this.context.router.push({
pathname: "/record",
state: this.props.location.state
});
},
onThreadCardSelected: function(syntheticEvent, reactId, e) {
var target = syntheticEvent.target.parentNode;
var threadId = target.getAttribute("data-thread-id");
var idx = this.state.selectedThreads.indexOf(threadId);
if(idx != -1) {
this.state.selectedThreads.splice(idx, 1);
this.setState({
selectedThreads: [].concat(this.state.selectedThreads)
});
}
else {
this.setState({
selectedThreads: [threadId].concat(this.state.selectedThreads)
});
}
},
activateThreadShareType: function() {
if(this.state.activeShareType == "thread") {
return;
}
this.setState({
activeShareType: 'thread'
});
},
activateFBShareType: function() {
if(this.state.activeShareType == "facebook") {
return;
}
this.setState({
activeShareType: 'facebook'
});
//this will store the record and generate a shareId
this.getFlux().actions.record.local.saveRecording({
type: "share"
});
/*var state1 = this.context.router.push({
pathname: '/review',
state: {
type: "profile",
role: "main"
}
});*/
//console.log("the state1 is " + state1);
//this.getFlux().actions.record.local.saveRecording(state1);
},
copytoclipboard: function(){
var copyText = document.getElementById("shareLink");
copyText.select();
document.execCommand("copy");
console.log("Copied the text: " + copyText.value);
},
onFinishRecord: function(e) {
if(e.target.classList.contains('inactive')) {
return;
}
if(this.props.location.state && ["profile", "sharereply"].indexOf(this.props.location.state.type) != -1) {
console.log(this.props.location.state);
this.getFlux().actions.record.local.saveRecording(this.props.location.state);
}
else if(this.state.activeShareType == "facebook") {
this.getFlux().actions.record.local.saveRecording({
type: "share"
});
}
else {
var data = {
type: "thread",
threadIds: this.state.selectedThreads
};
//we started recording from a thread, so we pass the userId to be able to return to this thread
//after saving
if(this.props.location.state && this.props.location.state.type == "thread") {
data.userId = this.props.location.state.userId;
}
this.getFlux().actions.record.local.saveRecording(data);
}
}
});
module.exports = Review;
I found my error!
The problem was that I initialized the require('react-share') in a variable reactShare and was using the component as
<FacebookShareButton url={shareLink} quote={title} className="social-media-icon">
<FacebookIcon size={32} round />
</FacebookShareButton>`
Instead, I should have initialized the require statement as
var FacebookShareButton = require('react-share');
Because of not declaring it properly React was yelling on me.
I hope this will save someones precious time. Cheers!

Custom angular directive controller not updating

I created my own angular directive which can simply be used as:
<basket-summary></basket-summary>
This element is used on my master template page (the index.html).
The directive is as follows:
/* Directive */
angular.module('ecommerceDirectives').directive('basketSummary', [function() {
return {
restrict : 'E',
scope: {},
replace: true,
controller : 'BasketController',
controllerAs: 'basketController',
bindToController: {
basketController : '='
},
templateUrl: function(element, attrs) {
if (typeof attrs.templateUrl == 'undefined') {
return 'app/views/basket-summary.html';
} else {
return attrs.templateUrl;
}
},
link: function (scope, element, attrs) {
console.log("test");
}
};
}]);
The templateUrl of this directive is as follows:
<div class="btn-group pull-right">
<a class="btn btn-warning" ng-click="basketController.viewBasket()"><span class="badge">{{basketController.getTotalQuantities()}}</span> <span class="hidden-xs">Shopping</span> Cart</a>
<button type="button" class="btn btn-warning dropdown-toggle" data-toggle="dropdown">
<span class="fa fa-caret-down"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu">
<div class="col-xs-12 cartItemHeader">
<h4>My Shopping Cart</h4>
</div>
<div class="quickCart" ng-repeat="cartItem in basketController.customerBasket.items">
<div class="col-xs-12 cartItemWrap">
<div class="col-xs-12 desc">{{cartItem.product.title}}</div>
<div class="col-xs-5 col-sm-8 price">{{cartItem.product.rrp_currency}} {{cartItem.product.rrp_amount}}</div>
<div class="col-xs-6 col-sm-3 units">Items: {{cartItem.quantity}}</div>
<div class="col-xs-1 trash"><a ng-click="basketController.deleteCartItem(cartItem.product.id)"><i class="fa fa-trash"></i></a></div>
</div>
</div>
</div>
And the BasketController is as follows:
/* Controller */
angular.module('ecommerceControllers').controller('BasketController', ['$rootScope', '$scope', '$route', '$location', 'CustomerBasketService', 'AppSettingService', 'StorageService', 'DEFAULT_CURRENCY_CODE', 'MERCHANT_ID_KEY', function($rootScope, $scope, $route, $location, CustomerBasketService, AppSettingService, StorageService, DEFAULT_CURRENCY_CODE, MERCHANT_ID_KEY) {
function basketProduct(product) {
this.id = product.id;
this.title = product.title;
this.categories = product.categories;
this.images = product.imaes;
this.created_on = product.created_on;
this.sku_code = product.sku_code;
this.lang = product.lang;
this.short_description = product.short_description;
this.attributes = product.attributes;
this.rrp_currency = product.rrp_currency;
this.rrp_amount = product.rrp_amount;
this.barcode_number = product.barcode_number;
this.last_modified_on = product.last_modified_on;
}
function basketItem(quantity, product) {
this.quantity = quantity;
this.product = new basketProduct(product);
}
function load() {
var basket = StorageService.get("customer_basket");
if (basket) {
for (var i = 0; i < basket.items.length; i++) {
var cartItem = basket.items[i];
cartItem = new basketItem(cartItem.quantity, cartItem.product);
basket.items[i] = cartItem;
}
}
return basket;
}
var basketController = this;
$scope.basketController = basketController;
basketController.customerBasket = load();
if (!basketController.customerBasket) {
basketController.customerBasket = {
shipping : null,
taxRate : null,
tax : null,
items : []
};
}
basketController.addCartItem = function(quantity, product) {
if (product == undefined || product == null) {
throw "No Product was specified.";
}
if (quantity == undefined || quantity == null) {
quantity = null;
}
var found = false;
if (basketController.customerBasket && basketController.customerBasket.items && basketController.customerBasket.items.length > 0) {
for (var i = 0; i < basketController.customerBasket.items.length; i++) {
var cartItem = basketController.customerBasket.items[i];
if (product.id === cartItem.product.id) {
found = true;
cartItem.quantity = cartItem.quantity + quantity;
if (cartItem.quantity < 1) {
basketController.customerBasket.items.splice(i, 1);
} else {
$rootScope.$broadcast('customerBasketItemUpdated', {item: cartItem});
}
}
}
}
if (!found) {
var cartItem = new basketItem(quantity, product);
basketController.customerBasket.items.push(cartItem);
$rootScope.$broadcast('customerBasketItemAdded', {item: cartItem});
}
basketController.saveBasket();
}
basketController.updateBasket = function() {
if (basketController.customerBasket && basketController.customerBasket.items && basketController.customerBasket.items.length > 0) {
for (var i = 0; i < basketController.customerBasket.items.length; i++) {
var cartItem = basketController.customerBasket.items[i];
if (cartItem.quantity < 1) {
basketController.customerBasket.items.splice(i, 1);
}
}
}
basketController.saveBasket();
}
basketController.deleteCartItem = function(productId) {
if (productId == undefined) {
throw "Product ID is required.";
}
if (basketController.customerBasket && basketController.customerBasket.items && basketController.customerBasket.items.length > 0) {
for (var i = 0; i < basketController.customerBasket.items.length; i++) {
var cartItem = basketController.customerBasket.items[i];
if (productId == cartItem.product.id) {
basketController.customerBasket.items.splice(i, 1);
}
}
}
//Save
basketController.saveBasket();
}
basketController.getCurrencyCode = function() {
var code = DEFAULT_CURRENCY_CODE;
if (basketController.customerBasket && basketController.customerBasket.items && basketController.customerBasket.items.length > 0) {
code = basketController.customerBasket.items[0].product.rrp_currency;
}
return code;
};
basketController.getTotalQuantities = function(id) {
var total = 0;
if (basketController.customerBasket && basketController.customerBasket.items && basketController.customerBasket.items.length > 0) {
for (var i = 0; i < basketController.customerBasket.items.length; i++) {
var cartItem = basketController.customerBasket.items[i];
if (id == undefined || id == cartItem.product.id) {
total += cartItem.quantity;
}
}
}
return total;
};
basketController.getTotalAmount = function(cartItem) {
var total = 0;
if (cartItem) {
total = (cartItem.quantity * cartItem.product.rrp_amount);
}
return total.toFixed(2);
};
basketController.getFinalTotalAmount = function() {
var total = 0;
if (basketController.customerBasket && basketController.customerBasket.items && basketController.customerBasket.items.length > 0) {
for (var i = 0; i < basketController.customerBasket.items.length; i++) {
var cartItem = basketController.customerBasket.items[i];
total += (cartItem.quantity * cartItem.product.rrp_amount);
}
}
return total.toFixed(2);
};
basketController.clearBasket = function() {
StorageService.set("customer_basket", null);
basketController.customerBasket = {
shipping : null,
taxRate : null,
tax : null,
items : []
};
$rootScope.$broadcast('customerBasketCleared', {});
}
basketController.saveBasket = function() {
if (basketController.customerBasket) {
StorageService.set("customer_basket", basketController.customerBasket);
$rootScope.$broadcast('customerBasketSaved', {});
}
}
basketController.checkout = function(serviceName, clearCart) {
if (serviceName == undefined || serviceName == null) {
serviceName = "PayPal";
}
switch (serviceName) {
case "PayPal":
basketController.checkoutPayPal(clearCart);
break;
default:
throw "Unknown checkout service '" + serviceName + "'.";
}
};
basketController.checkoutPayPal = function(clearCart) {
if (basketController.customerBasket && basketController.customerBasket.items && basketController.customerBasket.items.length > 0) {
// global data
var data = {
cmd: "_cart",
business: '', //parms.merchantID,
upload: "1",
rm: "2",
charset: "utf-8"
};
AppSettingService.getAppSetting(MERCHANT_ID_KEY).get().$promise
.then(function(result) {
data.business = result.value;
for (var i = 0; i < basketController.customerBasket.items.length; i++) {
var cartItem = basketController.customerBasket.items[i];
var ctr = i + 1;
data["item_number_" + ctr] = cartItem.product.sku_code;
data["item_name_" + ctr] = cartItem.product.title;
data["quantity_" + ctr] = cartItem.quantity;
data["amount_" + ctr] = cartItem.product.rrp_amount.toFixed(2);
}
// build form
var form = $('<form/></form>');
form.attr("action", "https://www.paypal.com/cgi-bin/webscr");
form.attr("method", "POST");
form.attr("style", "display:none;");
addFormFields(form, data);
$("body").append(form);
// submit form
form.submit();
form.remove();
if (clearCart) {
try {
basketController.clearBasket();
} catch (exception) {
}
}
}).catch(function(reason) {
console.log(reason);
});
}
};
basketController.viewBasket = function() {
$location.path("/basket");
$route.reload();
};
function addFormFields(form, data) {
if (data != null) {
$.each(data, function (name, value) {
if (value != null) {
var input = $("<input></input>").attr("type", "hidden").attr("name", name).val(value);
form.append(input);
}
});
}
}
return basketController;
}]);
My dilemma is as follows:
On my product page, I have product.html page (which is an angular view) and the "add to cart" button adds item to the cart but it doesn't update my cart summary button.
How do I make it that when I click the "add to cart" button that it update my cart and the number of items added to the cart?
The example image:
As you can see the orange button at the top right says that I have no items but there is 3 items in my cart already.
I tried various scoping allowed in directives but I seem to be failing to make it work.
PS: I am a newbie in AngularJS so please make your answer as simple to understand. :-)
The view product.html is linked to BasketController and this is the button that add item to cart.
<a class="btn btn-success btn-lg pull-right" role="button" ng-click="basketController.addCartItem(1, productController.selectedProduct)"><i class="fa fa-plus"></i> Add To Cart</a></div>
You have an isolated scope issue. The controller of your directive is not the same as the controller you want to use in your product page. See: scopes
I would suggest you to create a factory, which is always a singleton where you store your basket products and inject them in both, the directive and the products page

v-for and computed properties calling methods

I'm trying to update some properties on a VueJS object list, but I'm having some glitches.
Here's the HTML:
<div id="el">
<p>Total Chats: {{ chats.length }} ({{ unreadCount }} unread)</p>
<button v-on:click="__addChat(true)">Add a Chat</button>
<button v-on:click="__makeAllRead">Read All</button>
<pre>{{ $data | json }}</pre>
<ul>
<li v-for="chat in chats">
<p>
Message {{ chat.id }}
<span v-if="chat.unread"><strong>(UNREAD)</strong></span>
</p>
</li>
</ul>
</div>
And the Vue code:
var vm = new Vue({
el: '#el',
data: {
nextID : 2,
chats: {
'6fc5gh4j3kl_FIRST': {
id : 1,
unread : true,
body : Date(),
}
},
},
methods: {
__addChat: function (unread) {
var chat = {
id : this.nextID++,
unread : unread,
body : Date(),
};
this.chats[this.__makeHash()] = chat;
console.log(this.chats);
},
__makeAllRead : function() {
console.log(Object.keys(this.chats));
for ( var key in Object.keys(this.chats) ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) ) {
this.chats[key] = true;
}
}
},
__countUnread : function() {
var unread = 0;
for ( var key in Object.keys(this.chats) ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) && this.chats[key].unread ) {
unread++;
}
}
return unread;
},
__makeHash: function() {
return '6fc5gh4j3kl1AZ0' + Math.floor((Math.random() * 100) + 1);
},
},
ready: function() {
this.__addChat(false);
},
computed: {
unreadCount: function () {
console.log('counting...');
return this.countUnread();
}
}
});
Here's a Fiddle: http://jsfiddle.net/522aw2n5/7/
Things I cannot understand/fix on this code:
1) A computed property using a method to update the count
2) It displays only the object manually created, not the dynamically ones.
3) I cannot make all messages read by clicking a button.
This is Vue 1.0.0 RC2.
Could you, please, tell me what Am I doing wrong?
Answered on VueJS's Gitter
HTML
<div id="el">
<p>Total Chats: {{ totalChats }} ({{ unreadCount }} unread)</p>
<button v-on:click="__addChat(true)">Add a Chat</button>
<button v-on:click="__makeAllRead">Read All</button>
<pre>{{ $data | json }}</pre>
<ul>
<li v-for="chat in chats">
<p>
{{ chat.id }}
<span v-if="chat.unread"><strong>(UNREAD)</strong></span>
</p>
</li>
</ul>
</div>
Vue Code
var vm = new Vue({
el: '#el',
data: {
nextID : 2,
chats: {
'6fc5gh4j3kl_FIRST': {
id : 1,
unread : true,
body : Date(),
}
},
},
methods: {
__addChat: function (unread) {
var chat = {
id : this.nextID++,
unread : unread,
body : Date(),
};
this.$set('chats.' + this.__makeHash(), chat);
},
__makeAllRead : function() {
console.log(Object.keys(this.chats));
for ( var key in this.chats ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) ) {
this.chats[key].unread = false;
}
}
},
__makeHash: function() {
return 'fc5gh4j3kl1AZ0' + Math.floor((Math.random() * 100) + 1);
},
},
ready: function() {
this.__addChat(false);
},
computed: {
totalChats: function() {
var size = 0, key;
for (key in this.chats) {
if (this.chats.hasOwnProperty(key)) size++;
}
return size;
},
unreadCount: function () {
var unread = 0;
for ( var key in this.chats ) {
// if any tests are invalid
if ( this.chats.hasOwnProperty(key) && this.chats[key].unread ) {
unread++;
}
}
return unread;
}
}
});

Angular sets input field to ng-invalid-min when trying to update it dynamically

I am trying to update an <input type="number"> field depending on the chosen option in a <select>, as well as its min="" and max="", but the the input field gets red and empty : ionic puts these classes in the markup :
class="ng-valid-max ng-valid-number ng-dirty ng-invalid ng-invalid-min ng-invalid-required"
The console.logs on the typeof the input value indicates that they are indeed numbers.
Edit: If I comment the snippet of code under : //initialise the values in the weight and unit fields
then the bug disappears...
template.html
<div id="weightdata" class="row">
<div id="weighttext"> <!-- class="col-20 enteryourweighttext"> -->
My weight:
</div>
<input id="weightinput" type="number" name="userweight" min="{{data.minWeight}}" max="{{data.maxWeight}}" ng-model="data.userweight" ng-change="saveUserWeight()" required></input>
<div id="weightunitradios">
<ion-checkbox class="checkboxes" ng-model="data.weightunit" ng-true-value="kg" ng-false-value="lbs" ng-change="saveWeightUnit(); convertWeightInput();">kg</ion-checkbox>
<ion-checkbox class="checkboxes" ng-model="data.weightunit" ng-true-value="lbs" ng-false-value="kg" ng-change="saveWeightUnit(); convertWeightInput();">lbs</ion-checkbox>
</div>
</div>
controllers.js:
.controller('WeightlevelCtrl', function($scope, $ionicPopup, $timeout, sessionService) {
//initialise the values in the weight and unit fields
console.log(sessionService.get('weightunit'))
if (sessionService.get('weightunit')) {
$scope.data.weightunit = sessionService.get('weightunit');
console.log(sessionService.get('weightunit') );
} else {
$scope.data.weightunit = 'kg';
};
if ($scope.data.weightunit === 'kg'){
$scope.data.minWeight="30";
$scope.data.maxWeight="140";
} else {
$scope.data.minWeight="65";
$scope.data.maxWeight="310";
}
if (sessionService.get('userWeight')) {$scope.data.userweight = sessionService.get('userWeight') } else {$scope.data.userweight = 70};
if (sessionService.get('userLevel')) {$scope.data.levelvalue = sessionService.get('userLevel') } else {$scope.data.levelvalue = 5};
if (sessionService.get('weightunit')) {
$scope.data.weightunit = sessionService.get('weightunit');
console.log(sessionService.get('weightunit') );
} else {
$scope.data.weightunit = 'kg';
};
if ($scope.data.weightunit === 'kg'){
$scope.data.minWeight="30";
$scope.data.maxWeight="140";
} else {
$scope.data.minWeight="65";
$scope.data.maxWeight="310";
}
if (sessionService.get('userWeight')) {$scope.data.userweight = sessionService.get('userWeight') } else {$scope.data.userweight = 70};
if (sessionService.get('userLevel')) {$scope.data.levelvalue = sessionService.get('userLevel') } else {$scope.data.levelvalue = 5};
$scope.convertWeightInput = function () {
if ($scope.data.weightunit === 'kg'){
$scope.data.minWeight="30";
$scope.data.maxWeight="140";
$scope.data.userweight = parseFloat(Math.round(lbs2kg($scope.data.userweight)));
console.log(typeof $scope.data.userweight);
console.log($scope.data.userweight);
} else {
$scope.data.minWeight="65";
$scope.data.maxWeight="310";
$scope.data.userweight = parseFloat(Math.round(kg2lbs($scope.data.userweight)));
console.log(typeof $scope.data.userweight);
console.log($scope.data.userweight);
}
}
$scope.saveWeightUnit = function() {
sessionService.persist('weightunit', $scope.data.weightunit);
}
$scope.saveUserWeight = function() {
sessionService.persist('userWeight', $scope.data.userweight);
}
$scope.saveUserLevel = function() {
sessionService.persist('userLevel', $scope.data.levelvalue);
}
})
Screenshot:
as seen here https://github.com/angular/angular.js/issues/2404
we need to use ng-min and ng-max instead of min and max.
Actually I had to split the process into two functions like this :
if ($scope.data.weightunit === 'kg'){
$scope.data.minWeight=30;
$scope.data.maxWeight=140;
} else {
$scope.data.minWeight=65;
$scope.data.maxWeight=310;
}
if (sessionService.get('userWeight')) {$scope.data.userweight = parseInt(sessionService.get('userWeight')) } else {$scope.data.userweight = 70};
if (sessionService.get('userLevel')) {$scope.data.levelvalue = parseInt(sessionService.get('userLevel')) } else {$scope.data.levelvalue = 5};
$scope.changeMinMax = function () {
if ($scope.data.weightunit === 'kg'){
$scope.data.minWeight=30;
$scope.data.maxWeight=140;
} else {
$scope.data.minWeight=65;
$scope.data.maxWeight=310;
}
}
$scope.convertWeightInput = function () {
if ($scope.data.weightunit === 'kg'){
$scope.data.userweight = parseFloat(Math.round(lbs2kg($scope.data.userweight)));
console.log(typeof $scope.data.userweight);
console.log($scope.data.userweight);
} else {
$scope.data.userweight = parseFloat(Math.round(kg2lbs($scope.data.userweight)));
console.log(typeof $scope.data.userweight);
console.log($scope.data.userweight);
}
}

How to do the Logic behind the next button in angularjs wizard

I have a customers.create.html partial bound to the WizardController.
Then I have 3 customers.create1,2,3.html partial files bound to WizardController1,2,3
Each WizardController1,2 or 3 has an isValid() function. This function determines wether the user can proceed to the next step.
The next button at the bottom of the pasted html should be disabed if ALL ? isValid() functions are false...
Thats my question but the same time that seems not correct to me.
I guess I am not doing the Wizard correctly...
Can someone please guide me how I should proceed with the architecture that the bottom next button is disabled when the current step isValid function returns false, please.
How can I make a connection from the WizardController to any of the WizardController1,2 or 3 ?
Is Firing an event like broadcast a good direction?
<div class="btn-group">
<button class="btn" ng-class="{'btn-primary':isCurrentStep(0)}" ng-click="setCurrentStep(0)">One</button>
<button class="btn" ng-class="{'btn-primary':isCurrentStep(1)}" ng-click="setCurrentStep(1)">Two</button>
<button class="btn" ng-class="{'btn-primary':isCurrentStep(2)}" ng-click="setCurrentStep(2)">Three</button>
</div>
<div ng-switch="getCurrentStep()" ng-animate="'slide'" class="slide-frame">
<div ng-switch-when="one">
<div ng-controller="WizardController1" ng-include src="'../views/customers.create1.html'"></div>
</div>
<div ng-switch-when="two">
<div ng-controller="WizardController2" ng-include src="'../views/customers.create2.html'"></div>
</div>
<div ng-switch-when="three">
<div ng-controller="WizardController3" ng-include src="'../views/customers.create3.html'"></div>
</div>
</div>
<a class="btn" ng-click="handlePrevious()" ng-show="!isFirstStep()">Back</a>
<a class="btn btn-primary" ng-disabled="" ng-click="handleNext(dismiss)">{{getNextLabel()}}</a>
'use strict';
angular.module('myApp').controller('WizardController', function($scope) {
$scope.steps = ['one', 'two', 'three'];
$scope.step = 0;
$scope.wizard = { tacos: 2 };
$scope.isFirstStep = function() {
return $scope.step === 0;
};
$scope.isLastStep = function() {
return $scope.step === ($scope.steps.length - 1);
};
$scope.isCurrentStep = function(step) {
return $scope.step === step;
};
$scope.setCurrentStep = function(step) {
$scope.step = step;
};
$scope.getCurrentStep = function() {
return $scope.steps[$scope.step];
};
$scope.getNextLabel = function() {
return ($scope.isLastStep()) ? 'Submit' : 'Next';
};
$scope.handlePrevious = function() {
$scope.step -= ($scope.isFirstStep()) ? 0 : 1;
};
$scope.handleNext = function(dismiss) {
if($scope.isLastStep()) {
dismiss();
} else {
$scope.step += 1;
}
};
});
durandalJS wizard sample code which could be used to rewrite a wizard for angularJS:
define(['durandal/activator', 'viewmodels/step1', 'viewmodels/step2', 'knockout', 'plugins/dialog', 'durandal/app', 'services/dataservice'],
function (activator, Step1, Step2, ko, dialog, app, service) {
var ctor = function (viewMode, schoolyearId) {
debugger;
if (viewMode === 'edit') {
service.editSchoolyear(schoolyearId);
}
else if (viewMode === 'create') {
service.createSchoolyear();
}
var self = this;
var steps = [new Step1(), new Step2()];
var step = ko.observable(0); // Start with first step
self.activeStep = activator.create();
var stepsLength = steps.length;
this.hasPrevious = ko.computed(function () {
return step() > 0;
});
self.caption = ko.observable();
this.activeStep(steps[step()]);
this.hasNext = ko.computed(function () {
if ((step() === stepsLength - 1) && self.activeStep().isValid()) {
// save
self.caption('save');
return true;
} else if ((step() < stepsLength - 1) && self.activeStep().isValid()) {
self.caption('next');
return true;
}
});
this.isLastStep = function() {
return step() === stepsLength - 1;
}
this.next = function() {
if (this.isLastStep()) {
$.when(service.createTimeTable())
.done(function () {
app.trigger('savedTimeTable', { isSuccess: true });
})
.fail(function () {
app.trigger('savedTimeTable', { isSuccess: false });
});
}
else if (step() < stepsLength) {
step(step() + 1);
self.activeStep(steps[step()]);
}
}
this.previous = function() {
if (step() > 0) {
step(step() - 1);
self.activeStep(steps[step()]);
}
}
}
return ctor;
});

Resources