if statement inside knockout array - if-statement

Im trying to load a knockout observable array 25 items at a time using a count variable. The idea is that when you click a button you get another 25 items in the list. Sounds simple but Im useless with knockout.
I tried calling $root.getCount and $parent.getCount and put getCount in my list-view div as a value but none work. I might be over thinking it. All i want to do is put a named variable into the if statement where $getCount is. help would be awesome.
<div class="list-view" >
<ul data-bind="foreach: myBigList" class="shop_list">
<!-- ko if: $index() < $getCount -->
<li class="list_row">
</li>
<!-- /ko -->
</ul>
</div>
here's my view model
$(function () {
var viewModel = {
count: ko.observable(25),
getCount: function () {
return count;
},
updateCount: function () {
count+=count;
},
};
ko.applyBindings(viewModel);
})

I'm not sure I understand what you are really trying to achieve, but I'm going to assume you already have a big list of items that you want to display in groups of 25. You can achieve that using the visible binding:
<div class="list-view" >
<ul data-bind="foreach: myBigList" class="shop_list">
<li class="list_row" data-bind="visible: $index() < $parent.count()">
</li>
</ul>
</div>
Since count is an observable, to upate it's value you need to do this:
$(function () {
function ViewModel() {
this.count = ko.observable(25);
this.updateCount = function () {
var newCount = this.count() + 25;
this.count(newCount);
};
}
ko.applyBindings(new ViewModel());
})

Since count is an observable, you must use the function syntax to return it: return count();. If you want to add 25 to the count variable each time the updateCount method is called, you will need to hardcode the value.
$(function () {
var viewModel = {
count: ko.observable(25),
getCount: function () {
return count();
},
updateCount: function () {
count()+=25;
},
};
ko.applyBindings(viewModel);
})

Related

How can I display a menu item's contents without clicking on the item

I would like to display the contents of the first menu item, without clicking on it, making it the default contents displayed when the app is opened. I have tried everything I can think of. Console.log shows the value of the "selectedView" observable to be something like "View {title: "Event List", templateName: "EventList"}" so I've tried setting it to this value but it still does work.
<div class="inServMenu" data-bind="foreach: views">
</div>
<div data-bind="with: selectedView">
<div data-bind="template: { name: templateName }"></div>
</div>
<script id="EventList" type="text/html">
<span>"Here's the Event List..."</span>
</script>
<script id="RosterList" type="text/html">
<span>"Here's the Roster List..."</span>
</script> var View = function (title, templateName) {
this.title = title;
this.templateName = templateName;
};
// VIEWMODEL
var viewModel = {
selectedView: ko.observable(),
views: ko.observableArray([
new View('Event List', 'EventList'),
new View('Roster List', 'RosterList')
]),
}
ko.applyBindings(viewModel);```
[Here's a jsfiddle][1]
[1]: http://jsfiddle.net/jjfrick/hmfubkcr/18/
You'd need to slightly change your viewmodel constructor so that you can have a reference to it:
function ViewModel () {
var vm = this;
vm.views = ko.observableArray([
new View('Event List', 'EventList'),
new View('Roster List', 'RosterList')
]);
vm.selectedView = ko.observable(vm.views()[0])
}
ko.applyBindings(new ViewModel());

How can I scroll down to bottom of a specific div on page load in a chat conversation using Nuxt.js?

I want scroll down to the last div
<div v-for="(message, message_index) in messageArray" :key="message_index">
<div class="chatList">
</div>
</div>
I'm assuming you have a chat component where you want to scroll down to the last message on page load.
Although there are many ways to achieve this, I found this is the simplest one.
scrollIntoView() inside this.$nextTick(function () {}) gets the job done.
Bind your every div inside the loop with unique id. :id="`m-(some_unique_id)`">
<div v-for="(message, message_index) in messageArray" :key="message_index">
<div :id="`m-${message.id}`">
</div>
</div>
and get the element of the last index of messageArray. And tell the scrollIntoView to scroll down to that div.
script
<script>
mounted: {
this.getChatBoxUsersChats();
},
methods: {
getChatBoxUsersChats() {
this.$nextTick(function () {
let length = this.messageArray.length;
if (length > 0) {
let id = this.messageArray0[length - 1].id;
let element = document.getElementById("m-" + id);
element.scrollIntoView({ behavior: "smooth", block: "end" });
});
},
},
}
</script>

How to trigger component event in angular dart tests?

I'm using angular_test.dart to test my components. I want to test that clicking on a particular <li> will mark it as selected.
multiple_choice_quiz_component.html
<div>
<div class="contain-center">
<h1>{{quiz.getDescription}}</h1>
</div>
<div class="contain-center">
<ul>
<li *ngFor="let answer of quiz.getChoiceList"
(click)="onSelect(answer)"
[class.selected]="answer == selectedAnswer"
[class.correct]="correctAnswer && answer == selectedAnswer"
[class.incorrect]="!correctAnswer && answer == selectedAnswer"
>
{{answer}}
</li>
</ul>
</div>
</div>
multiple_choice_quiz_component.dart
class MultipleChoiceQuizComponent
{
String selectedAnswer;
String description;
bool correctAnswer = false;
Quiz quiz;
MultipleChoiceQuizComponent(QuizService quizService)
{
this.quiz = quizService.getQuiz();
}
void onSelect(String answer)
{
selectedAnswer = answer;
this.correctAnswer = this.quiz.isAnswer(answer);
}
}
test.dart
...
import 'package:angular_test/angular_test.dart';
....
group('My Tests', () {
test('should change li element to selected', () async {
var bed = new NgTestBed<MultipleChoiceQuizComponent>();
var fixture = await bed.create();
await fixture.update((MultipleChoiceQuizComponent Component) {
});
});});
In my test, how can I trigger a click on let's say the second <li> and evaluate that it has the selected property? And how do I mock the quiz service and inject it to the constructor?
I thought I wasn't going to figure it out, but I did.
Using a debug html test file helped a lot. On the console I could set breakpoints. Using the console I could navigate through the methods of these objects to find out what I needed to call.
NgTestBed bed = new NgTestBed<MultipleChoiceQuizComponent>();
NgTestFixture fixture = await bed.create();
Element incorrectAnswer = fixture.rootElement.querySelector('.quiz-choice:nth-child(2)');
incorrectAnswer.dispatchEvent(new MouseEvent('click'));
bool hasClass = incorrectAnswer.classes.contains('incorrect');
expect(true, hasClass);
You can use PageObjects to interact with the page:
https://github.com/google/pageloader

ReactJS Transitions - Why doesn't this work?

I'd like to transition one element as it changes to another element.
I've got 3 examples:
one that works, but uses a list of items that are kept around (jsfiddle)
one that doesnt work, and only keeps one item around, depending on the state (jsfiddle)
another one that doesn't work, that keeps both items around and hides/shows them (jsfiddle using hide/show)
What I want is more like the second one, which is a very slight variation of the first attempt that works.
Option 1:
/** #jsx React.DOM */
var ReactTransitionGroup = React.addons.TransitionGroup;
var TodoList = React.createClass({
getInitialState: function() {
return {items: ['hello', 'world', 'click', 'me']};
},
handleAdd: function() {
var newItems =
this.state.items.concat([prompt('Enter some text')]);
this.setState({items: newItems});
},
handleRemove: function(i) {
var newItems = this.state.items;
newItems.splice(i, 1)
this.setState({items: newItems});
},
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
{item}
</div>
);
}.bind(this));
return (
<div>
<div><button onClick={this.handleAdd} /></div>
<ReactTransitionGroup transitionName="example">
{items}
</ReactTransitionGroup>
</div>
);
}
});
var app = React.renderComponent(<TodoList />, document.body);
Option 2:
JSX that doesn't work, but is closer to what I'd like to do (really, hide one view, and show another)
/** #jsx React.DOM */
var ReactTransitionGroup = React.addons.TransitionGroup;
var Test = React.createClass({
getInitialState: function() {
return {showOne:true}
},
onClick: function() {
this.setState({showOne:! this.state.showOne});
},
render: function() {
var result;
if (this.state.showOne)
{
result = <div ref="a">One</div>
}
else
{
result = <div ref="a">Two</div>
}
return (
<div>
<div><button onClick={this.onClick}>switch state</button></div>
<ReactTransitionGroup transitionName="example">
{result}
</ReactTransitionGroup>
</div>
);
}
});
var app = React.renderComponent(<Test />, document.body);
Option 3:
Uses hide/show to keep the 2 views around, but still doesn't work.
/** #jsx React.DOM */
var ReactTransitionGroup = React.addons.TransitionGroup;
var Test = React.createClass({
getInitialState: function() {
return {showOne:true}
},
onClick: function() {
this.setState({showOne:! this.state.showOne});
},
render: function() {
var result;
var c1 = this.state.showOne ? "hide" : "show";
var c2 = this.state.showOne ? "show" : "hide";
return (
<div>
<div><button onClick={this.onClick}>switch state</button></div>
<ReactTransitionGroup transitionName="example">
<div className={c1}>One</div>
<div className={c2}>Two</div>
</ReactTransitionGroup>
</div>
);
}
});
var app = React.renderComponent(<Test />, document.body);
So long story short - How can I make a transition execute on switching from one main "component" to another? I don't get why option 1 works, but option 2 doesn't!
React is just changing the content of the DOM because that's all that changed. Give the elements unique keys to make them animate.
if (this.state.showOne)
{
result = <div key="one">One</div>
}
else
{
result = <div key="two">Two</div>
}
JSFiddle
I used Michelle Treys answer to solve a similar problem using React-Router (1.0.1). Its not clear from the api that the key is needed. I was following React-routers suggestion to render a routes children in a parent as follows:
render() {
return (
<div id='app-wrapper'>
<ReactTransitionGroup component='div' className='transition-wrapper'>
{this.props.children}
</ReactTransitionGroup>
</div>
);
}
However the componentWillEnter only triggered on page load. Following Michelle's solution, I cloned a the children as per the react-router updates and added a key as follows:
render() {
const { location } = this.props;
return (
<div id='app-wrapper'>
<ReactTransitionGroup component='div' className='transition-wrapper'>
{React.cloneElement(this.props.children, {
key: location.pathname,
})}
</ReactTransitionGroup>
</div>
);
}
Thanks for the fix. Cheers

Angular modal template not displaying

I'm somewhat new to Angular. I am trying to display a Bootstap 3 modal dialog when an invalid user role is detected. I cannot get my modal template to display. The behavior seems to work i.e. I can dismiss the faded overlay..I just don't see the actual modal template.
Bootstrap 3
AngularJS 1.0.7
AngularJS UI Bootstrap 0.6.0
Controller
gsApp.controller('MainController', ['$rootScope', '$scope', '$q', '$window', '$location', '$modal', 'ApplicationCache', 'UserService',
function MainController($rootScope, $scope, $q, $window, $location, $modal, ApplicationCache, UserService) {
$scope.userRole = "BadRole";
$scope.showBadRoleModel = function () {
var showBadRoleModelInstance = $modal.open({
templateUrl: "badRoleModal.html",
backdrop: true,
windowClass: 'modal',
controller: badRoleModalInstance,
resolve: {
items: function () {
return $scope.userRole;
}
}
});
}
var badRoleModalInstance = function($scope, $modalInstance, items){
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
}]);
HTML
<div class="row" ng-controller="MainController">
<script type="text/ng-template" id="badRoleModal.html">
<div class="modal-header">
<h3>I'm a modal!</h3>
</div>
<div class="modal-body">
<h2>body</h2>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn" ng-click="showBadRoleModel()">Show bad role modal</button>
</div>
AngularJs UI Bootstrap doesn't work with Bootstrap 3 yet.
See more details here: https://github.com/angular-ui/bootstrap/issues/331
Here's a reusable Angular directive that will hide and show a Bootstrap 3 (or 2.x) modal.
app.directive("modalShow", function () {
return {
restrict: "A",
scope: {
modalVisible: "="
},
link: function (scope, element, attrs) {
//Hide or show the modal
scope.showModal = function (visible) {
if (visible)
{
element.modal("show");
}
else
{
element.modal("hide");
}
}
//Check to see if the modal-visible attribute exists
if (!attrs.modalVisible)
{
//The attribute isn't defined, show the modal by default
scope.showModal(true);
}
else
{
//Watch for changes to the modal-visible attribute
scope.$watch("modalVisible", function (newValue, oldValue) {
scope.showModal(newValue);
});
//Update the visible value when the dialog is closed through UI actions (Ok, cancel, etc.)
element.bind("hide.bs.modal", function () {
scope.modalVisible = false;
if (!scope.$$phase && !scope.$root.$$phase)
scope.$apply();
});
}
}
};
});
Usage Example #1 - this assumes you want to show the modal - you could add ng-if as a condition
<div modal-show class="modal fade"> ...bootstrap modal... </div>
Usage Example #2 - this uses an Angular expression in the modal-visible attribute
<div modal-show modal-visible="showDialog" class="modal fade"> ...bootstrap modal... </div>
Another Example - to demo the controller interaction, you could add something like this to your controller and it will show the modal after 2 seconds and then hide it after 5 seconds.
$scope.showDialog = false;
$timeout(function () { $scope.showDialog = true; }, 2000)
$timeout(function () { $scope.showDialog = false; }, 5000)
I'm late to contribute to this question - created this directive for another question. Here are some related links: Simple Angular Directive for Bootstrap Modal and https://stackoverflow.com/a/19668616/1009125
Hope this helps.