I have such a snippet of ajax request:
<div>
<h4>Comments</h4>
<!-- <form action="/article/comment/create/{{ article.id }}" method='post'> -->
<form action="#">
<textarea class="form-control" rows="5" name='comment' id="commentContent"></textarea>
<br>
<button class="btn btn-primary" id="commentBtn">Post Your Comment</button>
</form>
</div>
</div><!--/class="col-xs-8 col-md-8">-->
</div><!-- row -->
<script src="/static/js/jquery-3.3.1.js"></script>
<script src="/static/js/jquery-csrf.js"></script>
<script>
$(document).ready(function(){
var article_id = article.id;
var num_pages = {{ page.num_pages }};
$("#commentBtn").on('mouseover', function(e){
e.preventDefualt();
alert("clicked")
var comment = $("#commentContent").val();
var param = {
"article_id": article.id
"content": comment};
$post("/comment/create/", param, function(data){
var ret = JSON.parse(data);
if (ret["status"] = "ok") {
$("#commentConent").val("");
window.location.href = "/article/detail/{{ article.id }}?page_number=" + num_pages;
} else {
alert(ret["msg"]);
}
});
});
});
</script>
I set the event type as mouseover,
However, when I place my mouse over the button "#commentBtn",
nothing occurs.
What's the problem it might be with my codes?
You have many syntax errors and typos in your code , and that's the cause of your problem , you write every thing correct , but I suggest you should use IDE like vscode to help you find this errors , IDEs help in finding undefined variables , or any syntax errors , to help you avoid this kind of problems and bugs , if you look at your code you'll see that ,
var num_pages = {{ page.num_pages }}; this code should be like this
var num_pages = page.num_pages ; if you try to extract num_pages into variable , also you can use destructuring which is ES6 feature
also you should change $post to $.post and e.preventDefualt(); to e.preventDefault();
I suggest that you should learn about ES6 features which will make your code better and enhance your development with JavaScript , things like const let and arrow functions and many great features , you can take an overview of this features here
es6-features
$(document).ready(function() {
// var article_id = article.id;
// var num_pages = {{ page.num_pages }};
$('#commentBtn').on('mouseover', function(e) {
e.preventDefault();
alert('clicked');
var comment = $('#commentContent').val();
var param = {
// "article_id": article.id
content: comment,
};
$.post('/comment/create/', param, function(data) {
var ret = JSON.parse(data);
if ((ret['status'] = 'ok')) {
$('#commentConent').val('');
window.location.href =
'/article/detail/{{ article.id }}?page_number=' + num_pages;
} else {
alert(ret['msg']);
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<h4>Comments</h4>
<!-- <form action="/article/comment/create/{{ article.id }}" method='post'> -->
<form action="#">
<textarea class="form-control" rows="5" name='comment' id="commentContent"></textarea>
<br>
<button class="btn btn-primary" id="commentBtn">Post Your Comment</button>
</form>
</div>
</div><!--/class="col-xs-8 col-md-8">-->
</div><!-- row -->
Typo, use:
e.preventDefault();
Also:
$.post
And, at the end:
$("#commentContent")
Related
I need to create a cookie method with the current time, which will first check the data (like_finger and article_id), and if there is no data, then add a like and update the date, if there is data, then do nothing.
I have a function
$likes = request()->cookie('like_finger');
$hours = 24;
if ($likes) {
Article::find($id)
->where('updated_at', '<', Carbon::now()->subHours($hours)->toDateTimeString())
->increment('like_finger');
}
But I can't check it yet, because I got confused in the add like button
I added a button to php.blade and created a function in js
<input type="button" id="start" value="Like Finger" onclick="startCombine(this)"> {{ $article->like_finger }}
function startCombine(startButton) {
startButton.disabled = true;
startButton.disabled = false;
}
How can I make sure that a like is added when true?
I want that when the button is clicked, one like is added, which will be stored in cookies for 24 hours, I wrote an approximate function of how the like should be added, but it is not perfect, since there is no button functionality
First of all, you should never store any logic in the client side. A great alternative for this kind of feature would be using the Laravel Aquantances package.
https://laravel-news.com/manage-friendships-likes-and-more-with-the-acquaintances-laravel-package
Anyway, since you want to do it with cookies;
We can actually do this a lot easier than thought.
Articles.php
class User extends Authenticatable
{
// ...
public static function hasLikedToday($articleId, string $type)
{
$articleLikesJson = \Cookie::get('article_likes', '{}');
$articleLikes = json_decode($articleLikesJson, true);
// Check if there are any likes for this article
if (! array_key_exists($articleId, $articleLikes)) {
return false;
}
// Check if there are any likes with the given type
if (! array_key_exists($type, $articleLikes[$articleId])) {
return false;
}
$likeDatetime = Carbon::createFromFormat('Y-m-d H:i:s', $articleLikes[$articleId][$type]);
return ! $likeDatetime->addDay()->lt(now());
}
public static function setLikeCookie($articleId, string $type)
{
// Initialize the cookie default
$articleLikesJson = \Cookie::get('article_likes', '[]');
$articleLikes = json_decode($articleLikesJson, true);
// Update the selected articles type
$articleLikes[$articleId][$type] = today()->format('Y-m-d H:i:s');
$articleLikesJson = json_encode($articleLikes);
return cookie()->forever('article_likes', $articleLikesJson);
}
}
The code above will allow us to is a user has liked an article and generate the cookie we want to set.
There are a couple important things you need to care about.
Not forgetting to send the cookie with the response.
Redirecting back to a page so that the cookies take effect.
I've made a very small example:
routes/web.php
Route::get('/test', function () {
$articleLikesJson = \Cookie::get('article_likes', '{}');
return view('test')->with([
'articleLikesJson' => $articleLikesJson,
]);
});
Route::post('/test', function () {
if ($like = request('like')) {
$articleId = request('article_id');
if (User::hasLikedToday($articleId, $like)) {
return response()
->json([
'message' => 'You have already liked the Article #'.$articleId.' with '.$like.'.',
]);
}
$cookie = User::setLikeCookie($articleId, $like);
return response()
->json([
'message' => 'Liked the Article #'.$articleId.' with '.$like.'.',
'cookie_json' => $cookie->getValue(),
])
->withCookie($cookie);
}
});
resources/views/test.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<meta name="csrf-token" content="{{ csrf_token() }}" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
</head>
<body>
<div class="container">
#if (session('success'))
<div class="alert alert-success" role="alert">
{{ session('success') }}
</div>
#endif
<pre id="cookie-json">{{ $articleLikesJson }}</pre>
<div class="row">
#foreach (range(1, 4) as $i)
<div class="col-3">
<div class="card">
<div class="card-header">
Article #{{ $i }}
</div>
<div class="card-body">
<h5 class="card-title">Special title treatment</h5>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="/test?like=heart&article_id={{ $i }}" class="btn btn-primary like-button">
Like Heart
</a>
<a href="/test?like=finger&article_id={{ $i }}" class="btn btn-primary like-button">
Like Finger
</a>
</div>
<div class="card-footer text-muted">
2 days ago
</div>
</div>
</div>
#endforeach
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/js/bootstrap.min.js" integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF" crossorigin="anonymous"></script>
<script>
$(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$('.like-button').on('click', function(event) {
event.preventDefault();
let href = $(this).attr('href');
$.ajax({
url: href,
type: 'POST',
success: function (response) {
alert(response.message)
$('#cookie-json').text(response.cookie_json)
}
})
});
});
</script>
</body>
</html>
In Blade you can have conditionals, like
#if (count($records) === 1)
I have one record!
#elseif (count($records) > 1)
I have multiple records!
#else
I don't have any records!
#endif
Example taken from https://laravel.com/docs/8.x/blade
Let's try to apply it on your specific issue
#if ($article->article_id && $article->like_finger)
<input type="button" id="start" value="Like Finger" onclick="startCombine(this)"> {{ $article->like_finger }}
#endif
Make an AJAX request in startCombine() when the button is clicked.
Your server code processing the like seems to use a cookie named like_finger, so before the request to the server is made you create that cookie:
const d = new Date();
d.setTime(d.getTime() + (24*60*60*1000)); // Expiry in milliseconds
document.cookie = "like_finger=" + d.toUTCString() +
";expires=" + d.toUTCString() +
";path=/";
(The cookie is set to expire after 24 h with the above values)
Then you want to send that to the server:
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "the_place_where_php_processing_code_is.php", true);
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.onreadystatechange = function() { // When status of the ongoing request changes
if (this.readyState == 4 && this.status == 200) {
// Server has processed the like request and is done
// You can do some "summary" here, like disabling the Like button
var response = this.responseText;
}
};
var data = {
id : 1, // The id of the article being liked, not sure how to retrieve that right now
};
xhttp.send(JSON.stringify(data));
..and then you use something like this in the receiving PHP code on the server:
$id = $request->input('id'); // $id = 1 (in this case, of course)
I have a problem changing items after searching.
I looked at similar threads but found no solution there :(
It looks like the first time the page loads well - the first time the entire Index.cshtml page is loaded which contains a collection of books in the selected category.
There is a search engine on the page - after searching for "manual" - ajax correctly replaces elements with those containing "manual" in the name.
Then when I enter something into the search engine a second time (for example "exercises") - the content of the page does not change any more.
I tried to debug and I see that new items are correctly downloaded from the database - the condition "if (Request.IsAjaxRequest ())" is true and the items are passed to partial view - there the "foreach" loop goes through them. Unfortunately, after _Partial, nothing happens.
I can't find a mistake - the strangest thing is that the first ajax call works fine - only the second (and subsequent) bad.
CatalogController.cs
public ActionResult Index(string categoryName = null, string searchQuery = null)
{
if (categoryName == null)
categoryName = (db.Categories.Find(1)).Name;
var category = db.Categories.Include("Books").Where(x => x.Name.ToLower() == categoryName).Single();
var books = category.Books.Where(x => (searchQuery == null || x.Title.ToLower().Contains(searchQuery.ToLower()) || x.SubTitle.ToLower().Contains(searchQuery.ToLower()) || x.Level.ToLower().Contains(searchQuery.ToLower())) && !x.Inaccessible);
if (Request.IsAjaxRequest())
return PartialView("_PartialBooksList", books);
else
return View(books);
}
Index.cshtml
<form class="o-search-form" id="search-form" method="get" data-ajax="true" data-ajax-target="#booksList">
<input class="o-search-input" id="search-filter" type="search" name="searchQuery" data-autocomplete-source="#Url.Action("SearchTips")" placeholder="Search" />
<input class="o-search-submit" type="submit" value="" />
</form>
<div class="row" id="booksList">
#Html.Partial("_PartialBooksList")
</div>
#section Scripts
{
<script src="~/Scripts/jquery-3.5.0.js"></script>
<script src="~/Scripts/jquery-ui-1.12.1.js"></script>
<script>
$(function () {
var setupAutoComplete = function () {
var $input = $(this);
var options =
{
source: $input.attr("data-autocomplete-source"),
select: function (event, ui) {
$input = $(this);
$input.val(ui.item.label);
var $form = $input.parents("form:first");
$form.submit();
}
};
$input.autocomplete(options);
};
var ajaxSubmit = function () {
var $form = $(this);
var settings = {
data: $(this).serialize(),
url: $(this).attr("action"),
type: $(this).attr("method")
};
$.ajax(settings).done(function (result) {
var $targetElement = $($form.data("ajax-target"));
var $newContent = $(result);
$($targetElement).replaceWith($newContent);
$newContent.effect("slide");
});
return false;
};
$("#search-filter").each(setupAutoComplete);
$("#search-form").submit(ajaxSubmit);
});
</script>
}
_PartialBooksList
#model IEnumerable<ImpressDev.Models.Book>
#using ImpressDev.Infrastructure
<div class="row">
#foreach (var book in Model)
{
<div class="col-12 col-xl-4">
<a class="o-shop-link" href="#Url.Action("Details", "Catalog", new { bookId = book.BookId })">
<div class="o-shop-item">
<img class="o-shop-img" src="#Url.BookPhotoSourcePath(book.PhotoSource)" />
<div class="o-shop-text">
<h2>#book.Title</h2>
<h6>#book.SubTitle - #book.Level - <b>#book.Price zł.</b></h6>
+ Add to cart
</div>
</div>
</a>
</div>
}
</div>
Please help
I am not sure if this is the case, but try to change this code:
$($targetElement).replaceWith($newContent);
To this:
$($targetElement).html($newContent);
I think the problem is the div element with id="booksList" is replaced after first search. So you don't have this element in the second search.
I looked through the code step by step and found a solution to my problem.
In the first search, replace id="booksList"
<div class="row" id="booksList">
#Html.Partial("_PartialBooksList")
</div>
partial view in which there was only without id = booksLists.
In the next search there was no ID in this place and there was nothing to replace.
i'm working on a project in angularJS using AJAX and it's a post / comment system with like buttons. Everything is working so far except reading comments from Database which is supposed to be done using a 2nd ng-repeat inside the first one that is reading the posts.
I can recieve the json with data fine going to the page servicoLeituraComments.php, all data is there. I think the problem is with ng-repeat but I'm not sure how am i suppose to do it when it's inside another, i already tried "comments" or "p.comments" on it and none work. Also anything i type inside the 2nd ng-repeat won't appear on page neither. Here is the code.
<script>
var app = angular.module('postsApp', []);
var interval;
app.controller('postsCtrl', function($scope) {
$scope.toggle = false;
$scope.texto = [];
$scope.comment = [];
$scope.comment = "";
$scope.comments = "";
$scope.posts = "";
$scope.texto = "";
$scope.idPost = 0;
$scope.showBox = function(p){
p.toggle = !p.toggle;
if(interval == 0){
interval = setInterval("angular.element($('#postsApp')).scope().servicoLeituraPosts()",1000);
}else{
clearInterval(interval);
interval = 0;
}
servicoLeituraComments(p);
};
$scope.iniciaTimer = function(){
interval = setInterval("angular.element($('#postsApp')).scope().servicoLeituraPosts()",1000);
};
$scope.servicoLeituraPosts = function(){
$.getJSON(
"servicoLeituraPosts.php",
{
},
function(jsonData)
{
$scope.posts = jsonData;
$scope.$apply();
});
};
$scope.servicoLeituraComments = function(p){
$.getJSON(
"servicoLeituraComments.php",
{
"idPost": p.idPost
},
function(jsonData)
{
$scope.comments = jsonData;
$scope.$apply();
});
};
$scope.addPost = function(){
$.post(
"addPostRest.php",
{
"texto" : $scope.texto
},
function(dados)
{
$scope.texto = dados.indexOf("OK") >= 0 ? "" : "FALHOU";
$scope.$apply();
}
);
};
$scope.addLike = function(idPost){
$.post(
"addLike.php",
{
"idPost" : $scope.idPost = idPost
},
function(dados)
{
$scope.texto = dados.indexOf("OK") >= 0 ? "" : "FALHOU";
$scope.$apply();
}
);
};
$scope.addComment = function(p){
$.post(
"addComentarioRest.php",
{
"comment" : p.comment,
"idPost" : p.idPost
},
function(dados)
{
$scope.texto = dados.indexOf("OK") >= 0 ? "" : "FALHOU";
$scope.$apply();
}
);
};
});
</script>
<div class="panel panel-default">
<div class="panel-heading">
POSTS
<a class="btn btn-success pull-right" href="posts.php"><span class="glyphicon glyphicon-refresh"/></a>
</div>
<div class="panel-body">
<div class="form-group">
<label for="texto">Texto::</label>
<textarea ng-model="texto" placeholder="Coloque aqui a mensagem..." class="form-control" rows="5" name="texto"></textarea>
</div>
<button ng-click="addPost()" class="btn btn-success btn-xs" type="button">Enviar</button>
</div>
</div>
<div class="posts" id="posts">
<div class='row ng-scope' ng-repeat="p in posts" >
<div class='col-md-12'>
{{ p.nome }} - {{ p.data }} <p><p>
{{ p.texto }} <p><p>
{{ p.numeroLikes }}
<button ng-click="addLike(p.idPost)" class="btn btn-default btn-xs" type="button">Like</button>
<span class="abrir_comentario" ng-click="showBox(p)">Comentários</span>
<div ng-show="p.toggle" id="comentarios">
<div class="comentarios">
<div class="form-group">
<textarea ng-model="p.comment" placeholder="Coloque aqui a mensagem..." class="form-control" rows="3" name="texto"></textarea>
</div>
<p><p><p><button ng-click="addComment(p)" class="btn btn-success btn-xs" type="button">Enviar</button>
<div class="comments" id="comments">
<div class='row ng-scope' ng-repeat="c in p.comments" >
<div class='col-md-12'>
{{ c.nome }} - {{ c.data }} <p><p>
{{ c.texto }} <p><p>
</div>
</div>
</div>
</div>
</div> <p>
</div>
</div>
</div>
Here is JSon array from servicoLeituraPosts.php
[
{
"idPost":"12",
"data":"2017-06-21 01:17:05",
"nome":"joao",
"texto":"Ola",
"idAutor":"3",
"numeroLikes":"3"
},
{
"idPost":"13",
"data":"2017-06-21 01:24:10",
"nome":"joao",
"texto":"Eu sou o joao",
"idAutor":"3",
"numeroLikes":"3"
}
]
And here is JSon array from servicoLeituraComments.php
[
{
"nome":"joao",
"texto":"12345",
"data":null},
{
"nome":"joao",
"texto":"1234",
"data":null
}
]
So there are two things I am seeing here. The first is that the JSON you are trying to get comments from doesn't have a comments property. If it did it would be like this:
{
"idPost":"12",
"data":"2017-06-21 01:17:05",
"nome":"joao",
"texto":"Ola",
"idAutor":"3",
"numeroLikes":"3"
"comments": [] //This is missing, these would be p.comments
}
The second thing I see is that you have a <textarea> with an ng-model="p.comments". Are you trying to use this to add comments to $scope.posts? If so you should change that model to something like ng-model="newComment" and addComment() should find $scope.newComment and push it to $scope.posts
Try this:
ng-click="addComment($index)"
$scope.addComment = function(index){
$scope.posts[index].comments.push($scope.newComment);
$scope.newComment = '';
}
Edit
It doesn't matter if you get the posts in one JSON, and the comments in another. The only problem I can see is the way your comments JSON is. There would need to be another field for the comments to know which posts to attach themselves to. Like this:
{
"nome":"joao",
"texto":"12345",
"data":null,
"idPost": "12" //This is how you would know that this comment goes to this post
}
Thank you all, i managed to solve this problem, i'm treating both ng-repeats individually one being inside the other, since I have 2 JSONs with data that relate with each other by ID.
I have multiple google captchas on page. Code:
<script>
var qqqq =function(captcha_response){
console.log('?')
}
var CaptchaCallback = function(){
$('.g-recaptcha').each(function(index, el) {
grecaptcha.render(el, {'sitekey' : '{{ recaptcha_key}}', 'callback': 'qqqq', 'theme': 'dark'});
});
};
</script>
<script src='https://www.google.com/recaptcha/api.js?onload=CaptchaCallback&render=explicit' async defer></script>
On the page there are several blocks for reCAPTCHA:
<div class="g-recaptcha"></div>
All reCAPTCHA's render well, all with dark theme, all do verifying work, but the callback function does not get called.
When I tried single reCAPTCHA with data-callback attribute, it worked well.
I was facing the same issue. After checking the documentation again I found my problem. Try to remove the single quotation marks around your function name.
Like this:
<script>
var qqqq =function(captcha_response){
console.log('?')
}
var CaptchaCallback = function(){
$('.g-recaptcha').each(function(index, el) {
grecaptcha.render(el, {'sitekey' : '{{ recaptcha_key}}', 'callback': qqqq });
});
};
</script>
Maybe this helps someone else as well :)
Steps to implement multimple recaptcha with a callback method for disable the submit button
1) Add the reference
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
2) Add the Code that will render the captcha widget
<script>
var CaptchaCallback = function () {
grecaptcha.render('RecaptchaField1', { 'sitekey': 'xxx', callback: 'recaptchaCallback1'});
grecaptcha.render('RecaptchaField2', { 'sitekey': 'xxx', callback: 'recaptchaCallback2' });
grecaptcha.render('RecaptchaField3', { 'sitekey': 'xxx', callback: 'recaptchaCallback3' });
};
</script>
3) Add the method to remove the disable property on the submit button
$('#GetHelpButton').prop('disabled', true);
function recaptchaCallback1()
{
$('#GetHelpButton').prop('disabled', false);
}
4) Add the widget inside a form
<form id="formContact" method="post" class="login-form margin-clear" action="Landing/SendContactForm">
<div class="form-group has-feedback">
<label class="control-label">Correo electronico</label>
<input name="EmailContact" value="" id="EmailContact" type="text" class="form-control" placeholder="">
<i class="fa fa-envelope form-control-feedback"></i>
</div>
<div id="RecaptchaField1"></div>
<button id="GetHelpButton" type="submit" data-sitekey="xxxx" class="btn btn-info col-md-12 g-recaptcha">Send</button>
Try setting a unique ID for each div and then use a for loop to iterate through them. Something like this:
window.onloadCallback = function() {
var captcha = ['recaptcha1' ,'recaptcha2', 'recaptcha3']; //put your IDs here
for(var x = 0; x < captcha.length; x++){
if($('#'+captcha[x]).length){
grecaptcha.render(captcha[x], {
'sitekey' : '{{ recaptcha_key}}',
'theme' : 'dark',
'callback': function() {
console.log("Woof");
}
});
}
}
};
Here is a fiddle
I have this html:
<div class="margin:0px; padding:0px; outline:0; border:0;" data-bind="with: notesViewModel">
<table class="table table-striped table-hover" data-bind="with: notes">
<thead><tr><th>Date Logged</th><th>Content</th><th>Logged By</th><th></th></tr>
</thead>
<tbody data-bind="foreach: allNotes">
<tr>
<td data-bind="text: date"></td>
<td data-bind="text: compressedContent"></td>
<td data-bind="text: logged"></td>
<td><img src="/images/detail.png" data-bind="click: $root.goToNote.bind($data, $index())" width="20" alt="Details"/></td>
</tr>
</tbody>
</table>
<div class="noteView" data-bind="with: chosenNote">
<div class="info">
<p><label>Date:</label><span data-bind="text: date"></span></p>
<p><label>Logged:</label><span data-bind="text: logged"></span></p>
</div>
<p class="message" data-bind="html: content"></p>
<button class="btn btn-default" data-bind="click: $root.toNotes">Back to Notes</button>
</div>
<div class="editor-label" style="margin-top:10px">
Notes
</div>
<div class="editor-field">
<textarea id="contact_note" rows="5" class="form-control" data-bind="value: $root.noteContent"></textarea>
<p data-bind="text: $root.characterCounter"></p>
<button class="btn btn-info" data-bind="click: $root.saveNotes">Save</button>
<div data-bind="html: $root.status">
</div>
</div>
</div>
And this JavaScript using knockout:
var notesViewModel = function () {
var self = this;
self.notes = ko.observable(null);
self.chosenNote = ko.observable();
self.allNotes = new Array();
self.user = "user1";
// behaviours
self.goToNote = function (noteIndex) {
self.notes(null);
self.chosenNote(new note(self.allNotes[noteIndex]));
};
self.toNotes = function () {
self.chosenNote(null);
self.notes({ allNotes: $.map(self.allNotes, function (item) { return new note(item); }) });
console.log(self.notes());
}
self.noteContent = ko.observable();
self.saveNotes = function () {
var request = $.ajax({
url: "EnquiryManagement/Contact/SaveNotes",
type: "GET",
dataType: "json",
data: { id: "1322dsa142d2131we2", content: self.noteContent() }
});
request.done(function (result, message) {
var mess = "";
var err = false;
var imgSrc = "";
if (message = "success") {
if (result.success) {
mess = "Successfully Updated";
imgSrc = "/images/tick.png";
self.allNotes.push({ date: new Date().toUTCString(), content: self.noteContent(), logged: self.user });
self.toNotes();
} else {
mess = "Server Error";
imgSrc = "/images/redcross.png";
err = true;
}
} else {
mess = "Ajax Client Error";
imgSrc = "/images/redcross.png";
err = true;
}
self.status(CRTBL.CreateMessageOutput(err, mess, imgSrc));
self.noteContent(null);
setTimeout(function () {
self.status(null);
}, 4000);
});
};
self.status = ko.observable();
self.characterCounter = ko.computed(function () {
return self.noteContent() == undefined ? 0 : self.noteContent().length;
});
};
var note = function (data) {
var self = this;
console.log(data.date);
self.date = CRTBL.FormatIsoDate(data.date);
self.content = data.content;
self.compressedContent = data.content == null ? "" : data.content.length < 25 ? data.content : data.content.substring(0, 25) + " ...";
self.logged = data.logged;
console.log(this);
};
ko.applyBindings(new notesViewModel());
When I first load the page it says:
Uncaught Error: Unable to parse bindings.
Message: ReferenceError: notes is not defined;
Bindings value: with: notes
However, I pass it null, so it shouldn't show anything, because when I do the function goToNote then do goToNotes it sets the notes observable to null
So why can't I start off with this null value?
The problem is where you have:
<div data-bind="with: notesViewModel">
That makes it look for a property "notesViewModel" within your notesViewModel, which does not exist.
If you only have one view model you can just remove that data binding and it will work fine.
If, however, you wish to apply your view model to just that div specifically and not the entire page, give it an ID or some other form of accessor, and add it as the second parameter in applyBindings, as follows:
HTML:
<div id="myDiv">
JS:
ko.applyBindings(new notesViewModel(), document.getElementById('myDiv'));
This is generally only necessary where you have multiple view models in the same page.
Like what bcmcfc has put, however, due to my scenario being a multi-viewModel scenario I don't think his solution is quite the right one.
In order to achieve the correct results, first of all I extrapolated out the self.notes = ko.observable(null); into a viewModel which makes doing the table binding far easier.
Then to fix the binding issues instead of setting an element for the bind to take place, I merely did this:
ko.applyBindings({
mainViewModel: new mainViewModel(),
notesViewModel: new notesViewModel()
});
In my original code I have two viewModels which is why I was getting this error. With this method the key is:
I don't create dependancies!
Instead of tieing the viewModel to a certain dom element which can change quite easily and cause having to go and changes things with ko, plus if I add more viewModels then it can get more complicated. I simply do:
data-bind="with: viewModel"
That way I can bind to any DOM object and I can have has many as I like.
This is the solution that solved my post.
Here is the jsfiddle