How to pass argument to onclick callback - yew function component - yew

How do I correctly pass an argument to an onclick event handler in a yew function component?
What I have:
#[function_component(Calculator)]
pub fn calulator() -> Html {
let navigator = use_navigator().unwrap();
let handle_formula_click = Callback::from(move |_| {
navigator.push(&AppRoute::Formula { id })
});
html! {
<div>
...
<button onclick={handle_formula_click}>
...
</button>
...
</div>
}
}
I would like to pass in a string to the handle_formula_click callback
What I want:
#[function_component(Calculator)]
pub fn calulator() -> Html {
let navigator = use_navigator().unwrap();
let handle_formula_click = Callback::from(move |id: String| {
navigator.push(&AppRoute::Formula { id })
});
html! {
<div>
...
<button onclick={handle_formula_click("fixed1"}>
...
</button>
...
</div>
}
}

You can do the following:
<button onclick={ move |_|{ handle_formula_click.emit("fixed1");}}>

Related

mat checkbox not clearing when cancel form button clicked

I have a list of cities in a form with check box. when trying cancel form , the list of checkboxes checked are not clearing . but when i uncheck each of the checkbox, it works
api-model.ts
export interface City{
city_Name: string;
}
class-model.ts
export class eModel {
cityList: Array<City>=[];
}
app.html
<div class="row">
<div class="column-3">
<div *ngFor="let data of cityData; let i=index">
<mat-checkbox color="primary" (change)="getCheckboxValues(data, i, $event)" >
{{data.city_Name}}
</mat-checkbox>
</div>
</div>
</div>
<button mat-raised-button class="cancel-button" (click)="Cancel()">Cancel</button>
app.ts
cityData: City[] = [];
ngOnInit(): void {
this.eModel.cityList = [];
loadCityList();
}
loadCityList() {
return this._getAPIservice.getCity().subscribe(data => {
this.cityData = data;
});
}
Cancel(): void {
this.eForm.resetForm({});
loadCityList();
this.eModel.cityList = [];
}
This can be achieved by using element reference variable.
Try this:
<div class="row">
<div class="column-3">
<div *ngFor="let data of cityData; let i=index">
<mat-checkbox #chkboxes color="primary" (change)="getCheckboxValues(data, i, $event)" >
{{data.city_Name}}
</mat-checkbox>
</div>
</div>
</div>
<button mat-raised-button class="cancel-button" (click)="Cancel()">Cancel</button>
In ts:
#ViewChildren('chkboxes') chkboxes: QueryList<any>; // Define this at the top
Cancel(){
this.chkboxes.forEach(x => x.checked = false);
}

bootstrap modal delete button is working but not return back from controller succesfully

I have Bootstrap modal in View.
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"><span id="eventTitle"></span></h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<button id="btnDelete" class="btn btn-default btn-sm pull-right">
<span class="fa fa-remove"></span> Sil
</button>
<button id="btnEdit" class="btn btn-default btn-sm pull-right" style="margin-right:5px;">
<span class="fa fa-edit"></span> Düzenle
</button>
<p id="pDetails"></p>
</div>
</div>
</div>
</div>
Script for delete button.
$('#btnDelete').click(function () {
if (selectedEvent != null && confirm('Are you sure?')) {
$.ajax({
type: "POST",
url: '/Planner/DeleteEvent',
data: { 'eventID': selectedEvent.eventID },
success: function (data) {
if (data.status) {
//Refresh the calender
FetchEventAndRenderCalendar();
$('#myModal').modal('hide');
}
},
error: function () {
alert('Failed');
}
})
}
})
And This is controller for delete operation
[HttpPost]
public JsonResult DeleteEvent(int eventID)
{
var status = false;
using (eteklifn_netEntities dc = new eteklifn_netEntities())
{
var v = dc.TBLEVENTS.Where(a => a.EventID == eventID).FirstOrDefault();
if (v != null)
{
dc.TBLEVENTS.Remove(v);
dc.SaveChanges();
status = true;
}
}
return new JsonResult { Data = new { status = status } };
}
When click the event, the modal opens. When click the btnDelete button event id goes to DeleteEvent Controller. Controller deletes succesfully event from database and return status= true. But still fail alert works. and in a way I do not understand page refresh.
//try this code.
$('#btnDelete').click(function () {
if (selectedEvent != null && confirm('Are you sure?')) {
$.ajax({
type: "POST",
url: '/Planner/DeleteEvent',
data: { 'eventID': selectedEvent.eventID },
success: function (response) {
if (response == "DeleteSucceeded") {
//Refresh the calender
FetchEventAndRenderCalendar();
$('#myModal').modal('hide');
}
}
})
}
})
//in your controller method try this
[HttpPost]
public JsonResult DeleteEvent(int eventID)
{
var status = false;
var v = dc.TBLEVENTS.Where(a => a.EventID == eventID).FirstOrDefault();
if (v != null)
{
using (eteklifn_netEntities dc = new eteklifn_netEntities())
{
dc.TBLEVENTS.Remove(v);
dc.SaveChanges();
status = true;
}
return Json("DeleteSucceeded");
}
else
{
return Json("DeleteFailed");
}
}

How do I assign my post method to my button in a view

I have the following code on my controller(ItemController).
[HttpPost]
public ActionResult LikeIncrement(VoteItem voteItem)
{
if (ModelState.IsValid)
{
using (MoraleCheckerDBEntities1 dc = new MoraleCheckerDBEntities1())
{
var currentItem = dc.VoteItems.FirstOrDefault(i => i.Id == voteItem.Id);
currentItem.ThumbsUp = voteItem.ThumbsUp++;
currentItem.ThumbsDown = voteItem.ThumbsDown + 0;
dc.SaveChanges();
}
}
return View(voteItem);
}
then I have this button on my View
<button type="button" class="btn btn-primary btn-lg" id="dislike-btn" >
<span class="glyphicon glyphicon-thumbs-down"></span>
</button>
I want everytime a user clicks this button to call that method.
Please.
You have to insert your button into a form element linked, with post method, to the action:
<form method="POST" action="Controller/LinkItem">
...form data elements ...
<button type="button" class="btn btn-primary btn-lg" id="dislike-btn" >
<span class="glyphicon glyphicon-thumbs-down"></span>
</button>
</form>
Or you can use ajax linking button to their action:
$('#dislike-btn').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var optionalData = $(this).closest('form').serialize();
$.post('Controller/LinkItem', optionalData, function(response) {
// do something to your controller, you should return a JSON object.
}
});
This is the minimal you can do:
jQuery
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#dislike-btn').on('click', function(){
$.ajax({
url: '#Url.Action("LikeIncrement", "Item")',
type: 'POST',
data: {voteItem: 'some data'},
contentType: "application/json;charset=utf-8",
success: function (result) {
alert("success");
},
error: function (jqXHR, status) {
// error handler
console.log(jqXHR);
alert('fail' + status);
}
});
});
</script>
View
<button type="button" class="btn btn-primary btn-lg" id="dislike-btn" >
<span class="glyphicon glyphicon-thumbs-down"></span>
</button>
Controller
[HttpPost]
public ActionResult LikeIncrement(VoteItem voteItem)
{
if (ModelState.IsValid)
{
using (MoraleCheckerDBEntities1 dc = new MoraleCheckerDBEntities1())
{
var currentItem = dc.VoteItems.FirstOrDefault(i => i.Id == voteItem.Id);
currentItem.ThumbsUp = voteItem.ThumbsUp++;
currentItem.ThumbsDown = voteItem.ThumbsDown + 0;
dc.SaveChanges();
}
}
return View(voteItem);
}
you should use Form tag and use submit button, like this:
<form action="/LikeIncrement" method="post">
<input type="submit" value="Submit">
</form>
and for input model (VoteItem), you should use Input with Name property, like this:
HTML form Tag
for MVC BeginForm in MVC
I hope help you.

MVC Full Calendar doesn´t show the events

I am implementing a calendar and I have encountered some difficulties because I am learning JavaScript alone and I have not mastered yet.
My problem is this: I can create the event and save it in the database, but the event and the color of it ... do not appear on the calendar ... can someone find out the solution or where is the problem?
If possible ... to create events ... being the color of this event always in random color?
View
<div id="calender"></div>
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><span id="eventTitle"></span></h4>
</div>
<div class="modal-body">
<button id="btnDelete" class="btn btn-default btn-sm pull-right">
<span class="glyphicon glyphicon-remove"></span> Remover
</button>
<button id="btnEdit" class="btn btn-default btn-sm pull-right" style="margin-right:5px;">
<span class="glyphicon glyphicon-pencil"></span> Editar
</button>
<p id="pDetails"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Fechar</button>
</div>
</div>
</div>
</div>
<div id="myModalSave" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Salvar Evento</h4>
</div>
<div class="modal-body">
<form class="col-md-12 form-horizontal">
<input type="hidden" id="hdID_Reserva" value="0" />
<div class="form-group">
<label>Cliente</label>
<input name="Nome" class="form-control" type="text" placeholder="Introduza o Nome" id="txtCliente">
<input type="hidden" id="txtID_Cliente" name="ID_Cliente" />
</div>
<div class="form-group">
<label>Data de Entrada</label>
<div class="input-group date" id="dtp1">
<input type="text" id="txtDataEntrada" name="DataEntrada" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
<div class="form-group">
<label>Data de Saida</label>
<div class="input-group date" id="dtp1">
<input type="text" id="txtDataSaida" name="DataSaida" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
<div class="form-group">
<label>Número Quarto</label>
#Html.DropDownList("ID_Quarto", null, "Selecione o Quarto", htmlAttributes: new { #class = "form-control" })
</div>
<div class="form-group">
<label>Número Pessoas</label>
<input id="txtNumeroPessoas" name="NumeroPessoas" class="form-control" />
</div>
<div class="form-group">
<label>Número Noites</label>
<input id="txtNumeroNoites" name="NumeroNoites" class="form-control" />
</div>
<div class="form-group">
<label>Preço</label>
<input id="txtPreço" name="Preço" class="form-control" />
</div>
<div class="form-group">
<label>Observações</label>
<input id="txtObservaçoes" name="Observaçoes" class="form-control" />
</div>
<button type="button" id="btnSave" class="btn btn-success">Salvar</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Fechar</button>
</form>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="~/AdminLTE/plugins/fullcalendar-3.9.0/fullcalendar.min.css" rel="stylesheet" />
<link href="~/AdminLTE/plugins/fullcalendar-3.9.0/fullcalendar.print.min.css" rel="stylesheet" media="print" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet" />
#section Scripts{
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="~/AdminLTE/plugins/fullcalendar-3.9.0/fullcalendar.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
<script>
$(document).ready(function () {
var events = [];
var selectedEvent = null;
FetchEventAndRenderCalendar();
function FetchEventAndRenderCalendar() {
events = [];
$.ajax({
type: "GET",
url: "/CalendárioReservas/GetEvents",
success: function (data) {
$.each(data, function (i, v) {
events.push({
eventID: v.ID_Reserva,
clienteID: v.ID_Cliente,
quartoID: v.ID_Quarto,
inicio: moment(v.DataEntrada),
fim: v.DataSaida != null ? moment(v.DataSaida) : null,
noites: v.NumeroNoites,
pessoas: v.NumeroPessoas,
preço: v.Preço,
obs: v.Observaçoes
});
})
GenerateCalender(events);
},
error: function (error) {
alert('failed');
}
})
}
function GenerateCalender(events) {
$('#calender').fullCalendar('destroy');
$('#calender').fullCalendar({
contentHeight: 400,
defaultDate: new Date(),
timeFormat: 'h(:mm)a',
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay,agenda'
},
eventLimit: true,
eventColor: '#378006',
events: events,
eventClick: function (calEvent, jsEvent, view) {
selectedEvent = calEvent;
$('#myModal #eventTitle').text(calEvent.clienteID);
var $quartoID = $('<div/>');
$quartoID.append($('<p/>').html('<b>DataEntrada:</b>' + calEvent.inicio.format("DD-MMM-YYYY HH:mm a")));
if (calEvent.fim != null) {
$quartoID.append($('<p/>').html('<b>DataSaida:</b>' + calEvent.fim.format("DD-MMM-YYYY HH:mm a")));
}
$quartoID.append($('<p/>').html('<b>ID_Quarto:</b>' + calEvent.quartoID));
$('#myModal #pDetails').empty().html($quartoID);
$('#myModal').modal();
},
selectable: true,
select: function (inicio, fim) {
selectedEvent = {
eventID: 0,
clienteID: '',
quartoID: '',
inicio: inicio,
fim: fim,
pessoas: '',
noites: '',
preço: '',
obs: ''
};
openAddEditForm();
$('#calendar').fullCalendar('unselect');
},
editable: true,
eventDrop: function (event) {
var data = {
ID_Reserva: event.eventID,
ID_Cliente: event.clienteID,
DataEntrada: event.inicio.format('DD/MM/YYYY HH:mm A'),
DataSaida: event.fim != null ? event.fim.format('DD/MM/YYYY HH:mm A') : null,
ID_Quarto: event.quartoID,
NumeroNoites: event.noites,
NumeroPessoas: event.pessoas,
Preço: event.preço,
Observaçoes: event.obs
};
SaveEvent(data);
}
})
}
$('#btnEdit').click(function () {
//Open modal dialog for edit event
openAddEditForm();
})
$('#btnDelete').click(function () {
if (selectedEvent != null && confirm('Are you sure?')) {
$.ajax({
type: "POST",
url: '/CalendárioReservas/DeleteEvent',
data: { 'eventID': selectedEvent.eventID },
success: function (data) {
if (data.status) {
//Refresh the calender
FetchEventAndRenderCalendar();
$('#myModal').modal('hide');
}
},
error: function () {
alert('Failed');
}
})
}
})
$('#dtp1,#dtp2').datetimepicker({
format: 'DD/MM/YYYY HH:mm A'
});
//$('#chkDiaTodo').change(function () {
// if ($(this).is(':checked')) {
// $('#divDataFim').hide();
// }
// else {
// $('#divDataFim').show();
// }
//});
function openAddEditForm() {
if (selectedEvent != null) {
$('#hdID_Reserva').val(selectedEvent.eventID);
$('#txtID_Cliente').val(selectedEvent.clienteID);
$('#txtDataEntrada').val(selectedEvent.inicio.format('DD/MM/YYYY HH:mm A'));
//$('#chkDiaTodo').prop("checked", selectedEvent.allDay || false);
//$('#chkDiaTodo').change();
$('#txtDataSaida').val(selectedEvent.fim != null ? selectedEvent.fim.format('DD/MM/YYYY HH:mm A') : '');
$('#ID_Quarto').val(selectedEvent.quartoID);
$('#txtNumeroNoites').val(selectedEvent.noites);
$('#txtNumeroPessoas').val(selectedEvent.pessoas);
$('#txtPreço').val(selectedEvent.preço);
$('#txtObservaçoes').val(selectedEvent.obs);
}
$('#myModal').modal('hide');
$('#myModalSave').modal();
}
$('#btnSave').click(function () {
//Validation/
if ($('#txtID_Cliente').val().trim() == "") {
alert('Introduza um Título');
return;
}
if ($('#txtDataEntrada').val().trim() == "") {
alert('Introduza uma Data de Início');
return;
}
//if ($('#chkDiaTodo').is(':checked') == false && $('#txtDataFim').val().trim() == "") {
// alert('Introduza uma Data de Fim');
// return;
//}
else {
var startDate = moment($('#txtDataEntrada').val(), "DD/MM/YYYY HH:mm A").toDate();
var endDate = moment($('#txtDataSaida').val(), "DD/MM/YYYY HH:mm A").toDate();
if (startDate > endDate) {
alert('Data de Fim Inválida');
return;
}
}
var data = {
ID_Reserva: $('#hdID_Reserva').val(),
ID_Cliente: $('#txtID_Cliente').val().trim(),
DataEntrada: $('#txtDataEntrada').val().trim(),
DataSaida: $('#txtDataSaida').val().trim(),
ID_Quarto: $('#ID_Quarto').val(),
NumeroPessoas: $('#txtNumeroPessoas').val(),
NumeroNoites: $('#txtNumeroNoites').val(),
Preço: $('#txtPreço').val(),
Observaçoes: $('#txtObservaçoes').val()
}
SaveEvent(data);
// call function for submit data to the server
})
function SaveEvent(data) {
$.ajax({
type: "POST",
url: '/CalendárioReservas/SaveEvent',
data: data,
success: function (data) {
if (data.status) {
//Refresh the calender
FetchEventAndRenderCalendar();
$('#myModalSave').modal('hide');
}
},
error: function () {
alert('Failed');
}
})
}
})
</script>
controller
namespace WebApplication.Controllers
{
public class CalendárioReservasController : Controller
{
private HotelEntities db = new HotelEntities();
// GET: CalendárioReservas
public ActionResult Index()
{
ViewBag.ID_Quarto = new SelectList(db.Quarto, "ID_Quarto", "ID_Quarto");
return View();
}
public JsonResult GetEvents()
{
try
{
var events = db.Reserva.Select(p => new
{
ID_Reserva = p.ID_Reserva,
ID_Cliente = p.ID_Cliente,
ID_Quarto = p.ID_Quarto,
DataEntrada = p.DataEntrada,
DataSaida = p.DataSaida,
NumeroNoites = p.NumeroNoites,
NumeroPessoas = p.NumeroPessoas,
Preço = p.Preço,
Observaçoes = p.Observaçoes
}).ToList();
return Json(events, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
[HttpPost]
public JsonResult SaveEvent(Reserva e)
{
var status = false;
using (HotelEntities dc = new HotelEntities())
{
if (e.ID_Reserva > 0)
{
//Update the event
var v = dc.Reserva.Where(a => a.ID_Reserva == e.ID_Reserva).FirstOrDefault();
if (v != null)
{
v.ID_Cliente = e.ID_Cliente;
v.DataEntrada = e.DataEntrada;
v.DataSaida = e.DataSaida;
v.ID_Quarto = e.ID_Quarto;
v.NumeroPessoas = e.NumeroPessoas;
v.NumeroNoites = e.NumeroNoites;
v.Preço = e.Preço;
v.Observaçoes = e.Observaçoes;
}
}
else
{
dc.Reserva.Add(e);
}
dc.SaveChanges();
status = true;
}
return new JsonResult { Data = new { status = status } };
}
[HttpPost]
public JsonResult DeleteEvent(int eventID)
{
var status = false;
using (HotelEntities dc = new HotelEntities())
{
var v = dc.Reserva.Where(a => a.ID_Reserva == eventID).FirstOrDefault();
if (v != null)
{
dc.Reserva.Remove(v);
dc.SaveChanges();
status = true;
}
}
return new JsonResult { Data = new { status = status } };
}
}
}
Model
public partial class Reserva
{
public int ID_Reserva { get; set; }
public int ID_Cliente { get; set; }
public int ID_Quarto { get; set; }
public System.DateTime DataEntrada { get; set; }
public Nullable<System.DateTime> DataSaida { get; set; }
public int NumeroPessoas { get; set; }
public Nullable<int> NumeroNoites { get; set; }
public Nullable<decimal> Preço { get; set; }
public string Observaçoes { get; set; }
public virtual Cliente Cliente { get; set; }
public virtual Quarto Quarto { get; set; }
}
Your event objects do not conform to the specification laid out at https://fullcalendar.io/docs/event-object .
Here is the problem:
$.each(data, function (i, v) {
events.push({
eventID: v.ID_Reserva,
clienteID: v.ID_Cliente,
quartoID: v.ID_Quarto,
inicio: moment(v.DataEntrada),
fim: v.DataSaida != null ? moment(v.DataSaida) : null,
noites: v.NumeroNoites,
pessoas: v.NumeroPessoas,
preço: v.Preço,
obs: v.Observaçoes
});
});
FullCalendar doesn't speak Portuguese. The event property names have to match the ones in the documentation otherwise it will ignore them. It doesn't magically know that inicio means start, for example. This means it cannot read any start time from your event, and therefore it doesn't know how to display it on the calendar.
Again as per the documentation, your events are also required to have a title, which you didn't appear to include at all.
Try this instead:
$.each(data, function (i, v) {
events.push({
id: v.ID_Reserva,
clienteID: v.ID_Cliente,
quartoID: v.ID_Quarto,
title: '[You need to choose something to put here]',
start: moment(v.DataEntrada),
end: v.DataSaida != null ? moment(v.DataSaida) : null,
noites: v.NumeroNoites,
pessoas: v.NumeroPessoas,
preço: v.Preço,
obs: v.Observaçoes
});
});
I have just changed the properties which matter for displaying the event. For other custom properties, you can call them anything you like, but the ones which have a defined purpose in fullCalendar must be named correctly.
P.S. You may need to change the code in your eventDrop function in a similar way.

Parameter in a controller function returns undefined ReferenceError

I'm going through this learning lab for AngularJS. I can get the example to work as-is (with a minor bug fix).
I'm also trying to learn some good coding practices concerning AngluarJS by referencing this guide. This has resulted in a js file that looks like this:
(function () {
'use strict';
angular.module('QuizApp', []);
angular.module('QuizApp').controller('QuizCtrl', QuizController);
function QuizController($http) {
var vm = this;
vm.answer = answer();
vm.answered = false;
vm.correctAnswer = false;
vm.nextQuestion = nextQuestion();
vm.options = [];
vm.sendAnswer = sendAnswer(option);
vm.title = "loading question...";
vm.working = false;
function answer() {
return vm.correctAnswer ? 'correct' : 'incorrect';
}
function nextQuestion() {
vm.working = true;
vm.answered = false;
vm.title = "loading question...";
vm.options = [];
$http.get("/api/trivia")
.success(function (data, status, headers, config) {
vm.options = data.options;
vm.title = data.title;
vm.answered = false;
vm.working = false;
}).error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong.";
vm.working = false;
});
}
function sendAnswer(option) {
vm.working = true;
vm.answered = true;
$http.post('/api/trivia', { 'questionId': option.questionId, 'optionId': option.id })
.success(function (data, status, headers, config) {
vm.correctAnswer = (data === true);
vm.working = false;
})
.error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong.";
vm.working = false;
});
}
};
})();
However, this code is throwing the following error when the page loads.
ReferenceError: 'option' is undefined
at QuizController (http://localhost:17640/Scripts/app/quiz-controller.js:16:9)
at invoke (http://localhost:17640/Scripts/angular.js:4473:7)
at Anonymous function (http://localhost:17640/Scripts/angular.js:9093:11)
at nodeLinkFn (http://localhost:17640/Scripts/angular.js:8205:13)
at compositeLinkFn (http://localhost:17640/Scripts/angular.js:7637:13)
at compositeLinkFn (http://localhost:17640/Scripts/angular.js:7641:13)
at compositeLinkFn (http://localhost:17640/Scripts/angular.js:7641:13)
at compositeLinkFn (http://localhost:17640/Scripts/angular.js:7641:13)
at compositeLinkFn (http://localhost:17640/Scripts/angular.js:7641:13)
at publicLinkFn (http://localhost:17640/Scripts/angular.js:7512:30)
For whatever reason, it appears to be attempting to execute sendAnswer immediately. Since it's failing, the javascript halts mid-way displaying the angular property name {{title}} on the page instead of rendering the question on the page. I've tried different ways of defining and calling vm.sendAnswer and function sendAnswer, without any luck.
For reference, here is the code to my view (note the ng-repeat on options - this view code works perfectly when following the lab exercise exactly):
<div id="bodyContainer" ng-app="QuizApp">
<section id="content">
<div class="container">
<div class="row">
<div class="flip-container text-center col-md-12" ng-controller="QuizCtrl" ng-init="nextQuestion()">
<div class="back" ng-class="{flip: answered, correct: correctAnswer, incorrect:!correctAnswer}">
<p class="lead">{{answer()}}</p>
<p>
<button class="btn btn-info btn-lg next option" ng-click="nextQuestion()" ng-disabled="working">Next Question</button>
</p>
</div>
<div class="front" ng-class="{flip: answered}">
<p class="lead">{{title}}</p>
<div class="row text-center">
<button class="btn btn-info btn-lg option" ng-repeat="option in options" ng-click="sendAnswer(option)" ng-disabled="working">{{option.title}}</button>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
How can I preserve my coding practice (essentially, avoid using $scope in this situation and declare all of my viewmodel properties at the top of the controller) yet get the function to operate properly?
Are you planning to send in
vm.options = [];
vm.sendAnswer = sendAnswer(option);
vm.options into the sendAnswer() function because option is not defined. you won't get an error if you enclose 'option' in a string and pass it into the function.But then you wouldn't be getting the object you want.
add this somewhere at the top var option = {}.
I have this example working now.
For starters, the controller properties that are plugged into functions just need to reference the names of the functions.
vm.answer = answer;
vm.nextQuestion = nextQuestion;
vm.sendAnswer = sendAnswer;
Then we need an alias for our controller on our view so we can reference it more easily.
<div class="flip-container text-center col-md-12" ng-controller="QuizCtrl as quiz" ng-init="quiz.nextQuestion()">
<div class="back" ng-class="{flip: quiz.answered, correct: quiz.correctAnswer, incorrect:!quiz.correctAnswer}">
<p class="lead">{{quiz.answer()}}</p>
<p>
<button class="btn btn-info btn-lg next option" ng-click="quiz.nextQuestion()" ng-disabled="quiz.working">Next Question</button>
</p>
</div>
<div class="front" ng-class="{flip: quiz.answered}">
<p class="lead">{{quiz.title}}</p>
<div class="row text-center">
<button class="btn btn-info btn-lg option" ng-repeat="option in quiz.options" ng-click="quiz.sendAnswer(option)" ng-disabled="quiz.working">{{option.title}}</button>
</div>
</div>
</div>
And that's pretty much it. Just clean up the property definitions in the angular controller and then utilize an alias for the controller on the view. Everything else is pretty much the same code as what's in the question.
Here's the complete code now. Angular controller:
(function () {
'use strict';
angular.module('QuizApp', []);
angular.module('QuizApp').controller('QuizCtrl', QuizController);
function QuizController($http) {
var vm = this;
vm.answer = answer;
vm.answered = false;
vm.correctAnswer = false;
vm.nextQuestion = nextQuestion;
vm.options = [];
vm.sendAnswer = sendAnswer;
vm.title = "loading question...";
vm.working = false;
function answer() {
return vm.correctAnswer ? 'correct' : 'incorrect';
};
function nextQuestion() {
vm.working = true;
vm.answered = false;
vm.title = "loading question...";
vm.options = [];
$http.get("/api/trivia")
.success(function (data, status, headers, config) {
var answerOptions = data.options;
while (answerOptions.length > 0){
var random = Math.floor(Math.random() * answerOptions.length, 0);
alert(random);
vm.options.push(answerOptions[random]);
answerOptions.splice(random, 1);
}
//vm.options = data.options;
vm.title = data.title;
vm.answered = false;
vm.working = false;
}).error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong.";
vm.working = false;
});
};
function sendAnswer(option)
{
vm.working = true;
vm.answered = true;
$http.post('/api/trivia', { 'questionId': option.questionId, 'optionId': option.id }).success(function (data, status, headers, config) {
vm.correctAnswer = (data === true);
}).error(function (data, status, headers, config) {
vm.title = "Oops... something went wrong";
});
vm.working = false;
}
};
})();
MVC Index view:
#{
ViewBag.Title = "Play";
}
<div id="bodyContainer" ng-app="QuizApp">
<section id="content">
<div class="container">
<div class="row">
<div class="flip-container text-center col-md-12" ng-controller="QuizCtrl as quiz" ng-init="quiz.nextQuestion()">
<div class="back" ng-class="{flip: quiz.answered, correct: quiz.correctAnswer, incorrect:!quiz.correctAnswer}">
<p class="lead">{{quiz.answer()}}</p>
<p>
<button class="btn btn-info btn-lg next option" ng-click="quiz.nextQuestion()" ng-disabled="quiz.working">Next Question</button>
</p>
</div>
<div class="front" ng-class="{flip: quiz.answered}">
<p class="lead">{{quiz.title}}</p>
<div class="row text-center">
<button class="btn btn-info btn-lg option" ng-repeat="option in quiz.options" ng-click="quiz.sendAnswer(option)" ng-disabled="quiz.working">{{option.title}}</button>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
#section scripts {
#Scripts.Render("~/Scripts/angular.js")
#Scripts.Render("~/Scripts/app/quiz-controller.js")
}

Resources