why won't my code update when I add a new Item to the list - forms

I am trying to allow an item to be pushed to a list of times that I looped through using Vue.js. I don't understand why when I click on the button the list item appears but the text doesn't.
HTML
<div id="root">
<input v-modle="newCat" v-on:keyup.enter="addKitty">
<button v-on:click="addKitty">
+add
</button>
<ul>
<li v-for="cat in cats">{{ cat.name }}</li>
</ul>
</div>
Vue.js
app = new Vue({
el: '#root',
data: {
cats:
[{name: 'kitkat'},
{ name: 'fish'},
{ name: 'henry'},
{ name: 'bosco'}],
//new data set
newCat: ''
},
methods: {
addKitty: function() {
this.cats.push({
name: this.newCat
})
this.newCat = ''
}
}
})

There is a typo in your code.
<input v-modle="newCat" v-on:keyup.enter="addKitty">
Should be:
<input v-model="newCat" v-on:keyup.enter="addKitty">
Notice the different spelling for v-model.

Related

How to change the state of a vue when you click the check button

I am creating a Todo Application using Vue.js, Express.js, and MongoDB.
I want to change the state of the fields that appear as v-for through the checkbox.
The code I want is to change the state of the text when the checkbox is checked and to show another element with v-if.
Here is the code I wrote: But it does not work.
If I have the wrong code, please help me.
List Component
<template>
<div class="todos">
<div v-for="todo in todos" v-bind:key="todo._id" class="todo">
<div>
<input type="checkbox" v-model="todo.done" v-on:click="completeTodo(todo)">
<del v-if="todo.done">{{todo.title}}</del>
<strong v-else>{{todo.title}}</strong>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
todos: {}
}
},
created () {
this.$http.get('/api/todos')
.then((response) => {
this.todos= response.data
})
},
methods: {
completeTodo (todo) {
todo.done = !todo.done
}
}
}
</script>
You don't need v-on:click="completeTodo(todo)". v-model is already doing the trick for you. Also, the todos in your code should be defined and instantiated as array not an object.
v-model is used for two way data binding. That means, whatever data you pass from your code will be bound to the checkbox value in this case and whenever a change is made from UI and value of checkbox is altered by user, that will be captured in v-model variable. v-model is a combo of :value prop and #change event in case of checkbox, hence, it is able to update data in both the ways.
Please refer this snippet.
var app = new Vue({
el: '#app',
data: {
todos: [
{
id: 1,
title: 'Study',
done: false
},
{
id: 2,
title: 'Work',
done: false
},
{
id: 3,
title: 'Play',
done: false
}
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="todos">
<div v-for="todo in todos" :key="todo.id">
<div>
<input type="checkbox" v-model="todo.done"/>
<del v-if="todo.done">{{todo.title}}</del>
<strong v-else>{{todo.title}}</strong>
</div>
</div>
</div>
</div>

Unable to get mizzao/meteor-autocomplete to work with collection

I am using mizzao/meteor-autocomplete and am having problems in trying to get it to work.
When viewing the page in my browser, I am getting no results at all when typing any text. I've created the appropriate collection:
Institutions = new Mongo.Collection("institutions");
and know that there is data in the actual db, however still no success.
I've included my files below.
publications.js (located in the server folder)
Meteor.publish('institutions', function(args) {
return Institutions.find({}, args);
});
registrationStart.js
I've two helpers; one that actually powers the search and the other that should be returning the institutions. I have also tried this with the token: '#' argument with no success.
if (Meteor.isClient) {
Template.registrationStart.helpers({
settings: function() {
return {
position: "top",
limit: 7,
rules: [{
collection: Institutions,
field: "name",
options: '',
matchAll: true,
template: Template.institutionSelectDisplay
}]
};
},
institutions: function() {
return Instititions.find();
}
});
Template.registrationStart.events({
"autocompleteselect input": function(event, template, doc) {
// Session.set(event.target.name, event.target.value);
console.log("selected: ", doc);
console.log("event.target.name: ", event.target.name);
console.log("event.target.value: ", event.target.value);
}
});
}
registrationStart.html template
<template name="registrationStart">
<div class="panel-body" id="loginForm">
<h2 class="pageTitle">veClient Registration</h2>
<form>
<div> </div>
<fieldset>
{{> inputAutocomplete settings=settings id="institution" class="input-xlarge" placeholder="type institution here"}}
</fieldset>
<div> </div>
<button type="submit" class="btn btn-primary btn-sm">Continue Registration</button>
</form>
</div>
</template>
And the template to be rendered
<template name="institutionSelectDisplay">
<p class="inst-state">{{city}}, {{state}}</p>
<p class="inst-name">{{name}}</p>
<p class="inst-description">{{email}}</p>
</template>
Problem resulted because there was no subscription to the "institutions" publication. So need to add a subscribe statement to the registrationStart.js file:
Meteor.subscribe('institutions');

How to push dynamic data to JavaScript object?

I am new to the Ionic Framework. I just started building a few functionalities in AngularJS. Here, what I want is to enter the email and booking ID of a user in an HTML page and then redirect it to other pages which displays all email ids and booking id... Here is my code:
Reservation.html:
<form ng-submit = "goBooking(data)">
<div class="list">
<label class="item item-input">
<input type="text" placeholder="Enter Your Email Id" ng-model="data.emailId" required>
</label>
<label class="item item-input">
<input type="text" placeholder="Enter Your Booking Id" ng-model="data.bookingID" required>
</label>
</div>
<div class="padding">
<input type="submit" class="button button-block button-positive" value = "Submit" />
</div>
</form>
</ion-content>
</ion-view>
Reservation.JS
Controller.js:
.controller('reservationCtrl', function($scope, $state, $stateParams) {
$scope.toDoListItems = [{
emailId: 'versha',
bookingID: '123'
}, {
emailId: 'rahul',
bookingID: '456'
}];
$scope.getTotal = function(){
return $scope.toDoListItems.length;
}
$scope.goBooking = function(data){
$scope.toDoListItems.push({emailId:data.emailId,bookingID:data.bookingID});
$state.go('myBookingDetails');
data.emailId = ' ';
data.bookingID = ' ';
};
});
myBookingDeatils.html:
<ion-view view-title="Hotel Reception">
<ion-content>
<ion-list>
<ion-item ng-controller = "reservationCtrl" ng-repeat="item in toDoListItems">
<p> Welcome {{item.emailId}} !!!! </p>
ion-item>
</ion-list>
</ion-content>
</ion-pane>
</ion-view>
After running this,
I am getting output as
Welcome, Versha!!
Welcome, Rahul!!
I am not getting that email ID and Booking ID. What I am entering on my Reservation.html. I think my input values are not being set in the toDoListItems.
Somewhere, this code is not inserting the values $scope.toDoListItems.push({emailId:data.emailId,bookingID:data.bookingID});
Please Suggest!! Thanks in Advance!!
I am assuming you are using the same controller for each state? When you change states you reload your controller, which resets your $scope.toDoListItems array to it's inital state. You are going to want to save your toDoListItems in a Service. So...
Controller:
.controller('reservationCtrl', function($scope, $state, $stateParams, toDo) {
$scope.getTotal = function(){
return toDo.toDoListItems.length;
}
$scope.goBooking = function(data){
toDo.toDoListItems.push({
emailId:data.emailId,
bookingID:data.bookingID
});
$state.go('myBookingDetails');
data.emailId = null;
data.bookingID = null;
};
});
Service:
.factory('toDo', [function () {
var toDoListItems = [{
emailId: 'versha',
bookingID: '123'
}, {
emailId: 'rahul',
bookingID: '456'
}];
return {
toDoListItems : toDoListItems
};
}]);
This will ensure that the data survives the state change, however if you want this data to persist permanently and stay on page reloads etc.. you will need to hook up a database, if you are purely a front end guy I suggest looking at Firebase
A very simple way to accomplish this would be to just use $localstorage.
Something like this:
$scope.goBooking = function(data){
$scope.toDoListItems.push({emailId:data.emailId,bookingID:data.bookingID});
$localstorage.setObject('toDoListItems', $scope.toDoListItems);
$state.go('myBookingDetails');
};
And then inside of your new view (where the controller and scope are getting refreshed as Jacob pointed out)
$scope.toDoListItems = $localstorage.getObject('toDoListItems');
You'll just need to add the $localstorage service to you services (detailed in link below). For more info on using localstorage with Ionic, visit: http://learn.ionicframework.com/formulas/localstorage/

Handle radio button form in Marionette js

I'm trying to construct a view in my app that will pop up polling questions in a modal dialog region. Maybe something like this for example:
What is your favorite color?
>Red
>Blue
>Green
>Yellow
>Other
Submit Vote
I've read that Marionette js doesn't support forms out of the box and that you are advised to handle on your own.
That structure above, branch and leaves (question and list of options), suggests CompositeView to me. Is that correct?
How do I trigger a model.save() to record the selection? An html form wants an action. I'm unclear on how to connect the form action to model.save().
My rough draft ItemView and CompositeView code is below. Am I in the ballpark? How should it be adjusted?
var PollOptionItemView = Marionette.ItemView.extend({
template: Handlebars.compile(
'<input type="radio" name="group{{pollNum}}" value="{{option}}">{{option}}<br>'
)
});
var PollOptionsListView = Marionette.CompositeView.extend({
template: Handlebars.compile(
//The question part
'<div id="poll">' +
'<div>{{question}}</div>' +
'</div>' +
//The list of options part
'<form name="pollQuestion" action="? what goes here ?">' +
'<div id="poll-options">' +
'</div>' +
'<input type="submit" value="Submit your vote">' +
'</form>'
),
itemView: PollOptionItemView,
appendHtml: function (compositeView, itemView, index) {
var childrenContainer = $(compositeView.$("#poll-options") || compositeView.el);
var children = childrenContainer.children();
if (children.size() === index) {
childrenContainer.append(itemView.el);
} else {
childrenContainer.children().eq(index).before(itemView.el);
}
}
});
MORE DETAILS:
My goal really is to build poll questions dynamically, meaning the questions and options are not known at runtime but rather are queried from a SQL database thereafter. If you were looking at my app I'd launch a poll on your screen via SignalR. In essence I'm telling your browser "hey, go get the contents of poll question #1 from the database and display them". My thought was that CompositeViews are best suited for this because they are data driven. The questions and corresponding options could be stored models and collections the CompositeView template could render them dynamically on demand. I have most of this wired and it looks good. My only issue seems to be the notion of what kind of template to render. A form? Or should my template just plop some radio buttons on the screen with a submit button below it and I write some javascript to try to determine what selection the user made? I'd like not to use a form at all and just use the backbone framework to handle the submission. That seems clean to me but perhaps not possible or wise? Not sure yet.
I'd use the following approach:
Create a collection of your survey questions
Create special itemviews for each type of question
In your CompositeView, choose the model itemView based on its type
Use a simple validation to see if all questions have been answered
Output an array of all questions and their results.
For an example implementation, see this fiddle: http://jsfiddle.net/Cardiff/QRdhT/
Fullscreen: http://jsfiddle.net/Cardiff/QRdhT/embedded/result/
Note:
Try it without answering all questions to see the validation at work
Check your console on success to view the results
The code
// Define data
var surveyData = [{
id: 1,
type: 'multiplechoice',
question: 'What color do you like?',
options: ["Red", "Green", "Insanely blue", "Yellow?"],
result: null,
validationmsg: "Please choose a color."
}, {
id: 2,
type: 'openquestion',
question: 'What food do you like?',
options: null,
result: null,
validationmsg: "Please explain what food you like."
}, {
id: 3,
type: 'checkbox',
question: 'What movie genres do you prefer?',
options: ["Comedy", "Action", "Awesome", "Adventure", "1D"],
result: null,
validationmsg: "Please choose at least one movie genre."
}];
// Setup models
var questionModel = Backbone.Model.extend({
defaults: {
type: null,
question: "",
options: null,
result: null,
validationmsg: "Please fill in this question."
},
validate: function () {
// Check if a result has been set, if not, invalidate
if (!this.get('result')) {
return false;
}
return true;
}
});
// Setup collection
var surveyCollection = Backbone.Collection.extend({
model: questionModel
});
var surveyCollectionInstance = new surveyCollection(surveyData);
console.log(surveyCollectionInstance);
// Define the ItemViews
/// Base itemView
var baseSurveyItemView = Marionette.ItemView.extend({
ui: {
warningmsg: '.warningmsg',
panel: '.panel'
},
events: {
'change': 'storeResult'
},
modelEvents: {
'showInvalidMessage': 'showInvalidMessage',
'hideInvalidMessage': 'hideInvalidMessage'
},
showInvalidMessage: function() {
// Show message
this.ui.warningmsg.show();
// Add warning class
this.ui.panel.addClass('panel-warningborder');
},
hideInvalidMessage: function() {
// Hide message
this.ui.warningmsg.hide();
// Remove warning class
this.ui.panel.removeClass('panel-warningborder');
}
});
/// Specific views
var multipleChoiceItemView = baseSurveyItemView.extend({
template: "#view-multiplechoice",
storeResult: function() {
var value = this.$el.find("input[type='radio']:checked").val();
this.model.set('result', value);
}
});
var openQuestionItemView = baseSurveyItemView.extend({
template: "#view-openquestion",
storeResult: function() {
var value = this.$el.find("textarea").val();
this.model.set('result', value);
}
});
var checkBoxItemView = baseSurveyItemView.extend({
template: "#view-checkbox",
storeResult: function() {
var value = $("input[type='checkbox']:checked").map(function(){
return $(this).val();
}).get();
this.model.set('result', (_.isEmpty(value)) ? null : value);
}
});
// Define a CompositeView
var surveyCompositeView = Marionette.CompositeView.extend({
template: "#survey",
ui: {
submitbutton: '.btn-primary'
},
events: {
'click #ui.submitbutton': 'submitSurvey'
},
itemViewContainer: ".questions",
itemViews: {
multiplechoice: multipleChoiceItemView,
openquestion: openQuestionItemView,
checkbox: checkBoxItemView
},
getItemView: function (item) {
// Get the view key for this item
var viewId = item.get('type');
// Get all defined views for this CompositeView
var itemViewObject = Marionette.getOption(this, "itemViews");
// Get correct view using given key
var itemView = itemViewObject[viewId];
if (!itemView) {
throwError("An `itemView` must be specified", "NoItemViewError");
}
return itemView;
},
submitSurvey: function() {
// Check if there are errors
var hasErrors = false;
_.each(this.collection.models, function(m) {
// Validate model
var modelValid = m.validate();
// If it's invalid, trigger event on model
if (!modelValid) {
m.trigger('showInvalidMessage');
hasErrors = true;
}
else {
m.trigger('hideInvalidMessage');
}
});
// Check to see if it has errors, if so, raise message, otherwise output.
if (hasErrors) {
alert('You haven\'t answered all questions yet, please check.');
}
else {
// No errors, parse results and log to console
var surveyResult = _.map(this.collection.models, function(m) {
return {
id: m.get('id'),
result: m.get('result')
}
});
// Log to console
alert('Success! Check your console for the results');
console.log(surveyResult);
// Close the survey view
rm.get('container').close();
}
}
});
// Create a region
var rm = new Marionette.RegionManager();
rm.addRegion("container", "#container");
// Create instance of composite view
var movieCompViewInstance = new surveyCompositeView({
collection: surveyCollectionInstance
});
// Show the survey
rm.get('container').show(movieCompViewInstance);
Templates
<script type="text/html" id="survey">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title" > A cool survey regarding your life </h3>
</div>
<div class="panel-body">
<div class="questions"></div>
<div class="submitbutton">
<button type="button" class="btn btn-primary">Submit survey!</button>
</div>
</div>
</div >
</script>
<script type="text/template" id="view-multiplechoice">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title" > <%= question %> </h4>
</div>
<div class="panel-body">
<div class="warningmsg"><%= validationmsg %></div>
<% _.each( options, function( option, index ){ %>
<div class="radio">
<label>
<input type="radio" name="optionsRadios" id="<%= index %>" value="<%= option %>"> <%= option %>
</label>
</div>
<% }); %>
</div>
</div>
</script>
<script type="text/template" id="view-openquestion">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title" > <%= question %> </h4>
</div>
<div class="panel-body">
<div class="warningmsg"><%= validationmsg %></div>
<textarea class="form-control" rows="3"></textarea>
</div>
</div >
</script>
<script type="text/template" id="view-checkbox">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title" > <%= question %> </h4>
</div>
<div class="panel-body">
<div class="warningmsg"><%= validationmsg %></div>
<% _.each( options, function( option, index ){ %>
<div class="checkbox">
<label>
<input type="checkbox" value="<%= option %>"> <%= option %>
</label>
</div>
<% }); %>
</div>
</div>
</script>
<div id="container"></div>
Update: Added handlebars example
Jsfiddle using handlebars: http://jsfiddle.net/Cardiff/YrEP8/

Ember.js: When is the value of an `<input/>` field persisted to the corresponding `Controller` value?

UPDATE: forgot to mention that I use Ember in version 1.0.0-rc2
Given I have the following (very simple) Ember.View object:
App.AuthenticationLoginFormView = Ember.View.extend({
tagName: 'form',
classes: ['ajax-form']
}
which is used within a Handlebars template like this:
{{#view App.AuthenticationLoginFormView }}
<div class="ajax-form__row">
<label>
Account:<br/>
{{ view Ember.TextField valueBinding="controller.account" }}
</label>
</div>
<div class="ajax-form__row">
<label>
Username:<br/>
{{ view Ember.TextField valueBinding="controller.username" }}
</label>
</div>
<div class="ajax-form__row">
<label>
Password:<br/>
{{ view Ember.TextField type="password" valueBinding="controller.password" }}
</label>
</div>
<div class="ajax-form__row">
<a href="" class="ajax-form__reset-link" {{action "reset" }} >Reset</a>
<button class="ajax-form__button" {{action "login" target="controller"}} >Login</button>
</div>
{{/view }}
and a Controller for the whole thing which looks like:
App.AuthenticationLoginController = Ember.Controller.extend({
account: null,
username: null,
password: null,
login: function() {
// if I call, for example, this.get('account') I get the correct value
}
});
as I've written in the code sample, I get the 'correct' value within the login function which is called on form submit. but if I try to interrupt the transitionTo action within the corresponding Route object, all values of the controller seem to be null:
App.AuthenticationLoginRoute = Ember.Route.extend({
events: {
reset: function(){
console.log(this.controller.get('account'); // <-- prints 'null'!
this.transitionTo('reset');
}
}
});
is it possible to get the value of the input fields even if there was no action executed on the controller? if yes, how would I implement it? do I need a listener for each Ember.TextField which is fired on a keyEvent?
No you don't need a listener on every Ember.TextField, extend it:
extend Ember.TextField and hook into the change event:
App.MyTextField = Ember.TextField.extend({
change: function() {
console.log(this.get('value'));
}
});
in your template:
{{ view App.MyTextField type="password" valueBinding="controller.password" }}
now everytime you type something in the textfield you should see a console output.
hope it helps.
EDIT:
App.AuthenticationLoginRoute = Ember.Route.extend({
events: {
reset: function(){
console.log(this.controllerFor('authenticationLogin').get('password')); // <-- what does this print?
this.transitionTo('reset');
}
}
});