Knockout JS - Geting a modal popup to edit items - javascript

Im new to knockoutJS and really loving it. I'm trying to build something very similar to this http://jsfiddle.net/mac2000/N2zNk/light/. I tried copying the code and adapting it to my need. The problem with that is that I get my data from the server using $.getJSON it seems that the jsfiddle example was made for a different format of data which just confuses me.
So instead of asking for help to find the issue with my code I rather take a different approach. Hopefully you guys wont mind. Im starting from scratch and trying to learn each steps so I know what im doing.
Here is my code so far, this works great to simply display my data on my table.
<script type="text/javascript">
function EmployeeModal() {
var self = this;
self.Employees = ko.observableArray([]);
$.getJSON("../../../../_vti_bin/listData.svc/GDI_PROD_Incidents?$filter=ÉtatValue%20ne%20%27Fermé%27&$orderby=PrioritéValue desc",
function (data) {
if (data.d.results) {
self.Employees(ko.toJS(data.d.results));
}
}
);
}
$(document).ready(function () {
ko.applyBindings(new EmployeeModal());
});
</script>
I made a template where each row has an edit button similar to the example but no fucntion of binding are done yet. Now what I would like to do is simply onlick pass the selected data to my modal and show my modal like so:
$('#myModal').modal('show');
This is the step im struggling the most with. Would any have any clear documentations for a noob or example, hints or any type of help I would take to get me in the right direction from here.

Assume you have them in a list like this:
<ul data-bind="foreach: Employees">
<li data-bind="text: fullName, click: showEmployee"/>
</ul>
What I'd recommend is to update your view model to look like this:
function EmployeeModal() {
var self = this;
self.Employees = ko.observableArray([]);
self.currentEmployee = ko.observable(null);
self.showEmployee = function(vm){
self.currentEmployee(vm);
$('#myModal').modal('show');
};
.... // rest of your view model here
}
The last piece will be using KO's with binding to wrap your modal
<div class="modal" id="myModal" data-bind="with: currentEmployee">
<h1 data-bind="text: fullName"></h1>
</div>
What this does is listen for the click event on an individual element and automatically pass the view model bound to that element to the click handler you defined. We're then taking that view model, storing it in its own observable and then showing the modal like normal. The key here is the with binding which only executes when there's data stored in the observable, and also sets the context of all nested code to be the employee stored in currentEmployee.
There's a lot there if you're new, but using a current style observable to track individual data from a list is a great paradigm to use with Knockout = )
P.S.. the http://learn.knockoutjs.com/ tutorials are really great to work through if you've yet to do so.

Related

Options to make jQuery Ajax code more efficient / logical

I have the following HTML to display content pulled from an ajax script (ajax.php):
HTML
<ul class="list-unstyled" id="var_adjectives"><li><a href='#'>Loading...</a></li></ul>
<button id="37" onclick='update_adjectives();'>Refresh</button>
<hr />
<ul class="list-unstyled" id="var_brands"><li><a href='#'>Loading...</a></li></ul>
<button id="37" onclick='update_brands();'>Refresh</button>
<hr />
<ul class="list-unstyled" id="var_clothes"><li><a href='#'>Loading...</a></li></ul>
<button id="37" onclick='update_clothes();'>Refresh</button>
<hr />
When the page first loads, the following JS is used to populate the list items against the relevant <ul> tag (passing in two parameters each time):
Javascript Page Load
$(document).ready(function(){
$.post('ajax.php',{u:37,n:1} ,function(data){ var this_record = data.output; $('#var_adjectives').html(this_record);},'json');
$.post('ajax.php',{u:37,n:33},function(data){ var this_record = data.output; $('#var_brands').html(this_record);},'json');
$.post('ajax.php',{u:37,n:67},function(data){ var this_record = data.output; $('#var_clothes').html(this_record);},'json');
});
The refresh button can be used to refresh the content in the relevant <ul> tag, calling the following relevant JS function, from the onclick event on each of the 3 buttons:
Javascript Refresh Functions
function update_adjectives() {
$.post('ajax.php'
, {u:37,n:1}
, function(data){ var this_record = data.output; $('#var_adjectives').html(this_record); }
, 'json')
};
function update_brands() {
$.post('ajax.php'
, {u:37,n:33}
, function(data){ var this_record = data.output; $('#var_brands').html(this_record); }
, 'json')
};
function update_clothes() {
$.post('ajax.php'
, {u:37,n:67}
, function(data){ var this_record = data.output; $('#var_clothes').html(this_record); }
, 'json')
};
As you can see, there is a lot of overlap in the basic design of the JS.
I have these questions:
I am stuck working out how I can end up with one single line in the block of JS used to populate content when the page first loads.
I'd like to only have 1 function used to refresh content - because in my example above I have 3 blocks, but in my real page I have about 30 blocks.
While the JS is created by the PHP code when the page loads (rather than me writing it long-hand), it still would be nice to have much cleaner code which avoids having e.g. 30 refresh functions and 30 lines of code to populate each of the different <ul> IDs when first loading the page.
In each case, I can see I would need to pass an ID of relevant <ul> but I am tied up in knots working out if I can achieve what I'm trying to do.
Probably there are many things wrong with using the onclick event too!
Any advice would be much appreciated, thank you.
The most likely blocker is your API endpoint design. According to what you posted, you must access one category at a time and that must be done by sending the {u:N,n:N} combo object as the body of the POST request.
It would simplify things greatly if your endpoint accepted a different object. Something like {category:'name'} would allow greater flexibility.
You could use {category: 'all'} for the initial view of all categories and use {category: 'clothes'} for individual categories for the update/refresh.
Extending that to the click of the refresh buttons. You can use a single event handler and event bubbling to deal with every button click.
First you would add the event handler to containing element for all the <ul> elements.
Given this layout:
<div id='container'>
<ul><li><span>loading...</span></li></ul>
<button data-category="adjectives">Refresh</button>
<ul><li><span>loading...</span></li></ul>
<button data-category="brands">Refresh</button>
<ul><li><span>loading...</span></li></ul>
<button data-category="clothes">Refresh</button>
</div>
You can react to all the button clicks like this:
document.getElementById('container').addEventListener('click', update);
The update() event handler can determine which button was clicked by checking out the data- attribute on the button. Then, make the AJAX request and place the data into the correct <ul> by finding the closest or the prev() sibling <ul> element.
function update() {
const category = this.dataset.category;
$.post('ajax.php', {category: category}
, function(data) {
$('button').data(category).prev('ul').html(data.output);
}, 'json')
};

meteor comments-ui: comments appear then immediately disappear

I'm pretty new to Meteor and I'm struggling with arkham:comments-ui.
Here's a brief overview of what I'm doing. I hope it's not too detailed.
I'm subscribed to a published collection called 'articles'.
Articles = new Mongo.Collection("articles");
I'm iterating through this on load to display a preview of each article in the client via a template named 'articlepreview'.
Template.body.helpers({
articles: function(){
return Articles.find({}, {sort: {createdAt: -1}});
}
});
I've added the unique id of each article to a custom attribute (data-id) of the 'read more' button at the bottom of each preview.
<template name="articlepreview">
<h2>{{head}}</h2>
<p>{{{summary}}}</p>
<p class="readmore" data-id="{{_id}}">Read more</p>
</template>
I've added an event listener for this button which gets the custom attribute and calls a function to display the full article that was clicked as well as setting a Session variable with the unique id.
"click .readmore": function (event) {
event.preventDefault();
var articleID = event.target.getAttribute("data-id");
Session.set('articleUID',articleID);
Meteor.call("loadArticle", articleID);
}
This function populates a template named 'articlefull' via a helper; essentially I use Session.set to set a variable containing the text of the full article by using findOne with the unique ID that has been set.
HELPER:
Template.articlefull.helpers({
articlebody: function () {
return Session.get('articlebody');
},
uniqueid: function(){
return Session.get('articleUID');
}
});
TEMPLATE:
<template name="articlefull">
<div id="article">
<p>{{{articlebody}}}</p>
</div>
<div id="comments" class="comment-section">
{{> commentsBox id=uniqueid}}
</div>
</template>
Part of this template is a comment box. I'm setting the id of the comment box to match that of the article loaded, but something really odd happens at this point: the comments box allows me to type a comment and click 'Add', but once I do the comment briefly flashes on the screen and then disappears.
Any thoughts on what I'm doing wrong? If I pop {{uniqueid}} into the template just below the comment box it displays the right value, which means it is getting pulled through, but something is still going wrong...
PS: Please also tell me if I'm going about this in totally the wrong way. I'm sure there's a simpler way to do what I'm trying to but as I said, I'm new to this. Thanks!
Based on your detailed description about your implementation, I assume that this issue occurs due to a missing publish and subscribe function for your Comments collection.
Depending on your use case, you'll need to add Meteor.publish(name, func) and Meteor.subscribe(name, [arg1, arg2...], [callbacks]) functions.
Meteor.publish('allComments', function() {
return Comments.getAll();
});
Meteor.publish('articleComments', function(docId) {
return Comments.get(docId);
});
Meteor.subscribe('allComments');
Meteor.subscribe('articleComments', Session.get('articleUID'));

get the text of div using angularjs

i want to get the text of div using angularjs . I have this code
<div ng-click="update()" id="myform.value">Here </div>
where as my controller is something like this
var myapp= angular.module("myapp",[]);
myapp.controller("HelloController",function($scope,$http){
$scope.myform ={};
function update()
{
// If i have a textbox i can get its value from below alert
alert($scope.myform.value);
}
});
Can anyone also recommand me any good link for angularjs . I dont find angularjs reference as a learning source .
You should send the click event in the function, your html code should be :
<div ng-click="update($event)" id="myform.value">Here </div>
And your update function should have the event parameter which you'll get the div element from and then get the text from the element like this :
function update(event)
{
alert(event.target.innerHTML);
}
i just thought i put together a proper answer for everybody looking into this question later.
Whenever you do have the desire to change dom elements in angular you need to make a step back and think once more what exactly you want to achieve. Chances are you are doing something wring (unless you are in a link function there you should handle exactly that).
So where is the value comming, it should not come from the dom itself, it should be within your controller and brought into the dom with a ng-bind or {{ }} expression like:
<div>{{ likeText }}</div>
In the controller now you can change the text as needed by doing:
$scope.likeText = 'Like';
$scope.update = function() {
$scope.likeText = 'dislike';
}
For angular tutorials there is a good resource here -> http://angular.codeschool.com/
Redefine your function as
$scope.update = function() {
alert($scope.myform.value);
}
A better way to do it would be to use ng-model
https://docs.angularjs.org/api/ng/directive/ngModel
Check the example, these docs can be a bit wordy

Updating Variable in HTML with JQuery

I'm a beginner programmer and I'm building a game. Whenever the player clicks on the gold image, he should get 1 gold. So I have the following HTML piece of code:
<li id="gold">Gold: 0</li>
That's the starting gold, and through JQuery I update that with:
$('#gold-image').click(function() {
gold++;
$('#gold').replaceWith('<li id="gold">Gold: ' + gold + '</li>');
});
But I don't feel that's the best way to update how much gold the player has. Is there a way that I can write in the HTML to update the variable whenever it's being changed or something like that without having to replace that whole item?
Later in the game there will be many functions running at the same time and increasing the gold number, so I think replacing HTML code is not the optimal way.
Try this with your existing div <div id="gold">Gold: 0</div>:
$('#gold-image').click(function() {
gold++;
$('#gold').html('Gold: ' + gold);
});
Although the above code would work. I would NOT use jQuery for something like this. There are other frameworks which would be way better for such applications. For example you can take a look at AngularJS or Ember.
The same functionality can be achieved using the two-way binding with AngularJS.
1) the markup:
<div controller="GameCtrl">
<img src="/path/to/img.png" ng-click="goldClicked()">
<div>Gold {{ gold }}</div>
</div>
2) the javascript code
app.controller('GameCtrl', function($scope) {
$scope.gold = 0;
$scope.goldClicked = function() {
$scope.gold += 1;
};
});
The code is very very simple and you do not need to deal with selectors. Every time you change the gold (or any other variable) it will automatically be updated in the DOM. You will automatically get modular code and dependency injection. In addition you will write everything declaratively and your code will be much easier to read and easy to change in future.
UPDATE: Here is a working AngularJS fiddle: http://jsfiddle.net/absolutemystery/7WgYK/
Or, using a div only around the number (e.g., <div id="gold">0</div>),
$('#gold-image').click(function() {
$('#gold').html(++gold);
});
You could user Ember.js for this kind of thing. Ember.js its a MVC javascript library.
In this case:
<li id="gold">Gold: {{YourController.goldAmmount}}</li>
and them in your controler you only have to call the function updateAmmount():
var YourController= Em.ArrayController.create({
goldAmmount : 0,
updateAmmount : function(){
this.goldAmmount++;
}
})
If you can add a <span> element it would make it a little cleaner:
HTML:
<li>Gold: <span id="gold">0</span></li>
JAVASCRIPT:
$('#gold-image').click(function() {
gold++;
$('#gold').text(gold);
});
You can use custom events for that. Everytime gold value updates, you can trigger an event, passing an argument, for example:
$('#gold-image').click(function() {
gold++;
jQuery.event.trigger({type: "onGoldUpdate",val:gold});
});
After that, you can be always listening to that event and do whatever you want with this information, like this:
jQuery(document).on("onGoldUpdate", function(e){
var goldValue = e.val;
jQuery('.gold .value').html(goldValue);
});
And on HTML part, you can put a span around the value:
<li id="gold">Gold: <span class="value">0</span></li>
You could use a simple MVVM solution for your needs, for example Knockout.js. You can create a model and bind it's values to a place in your html and anytime you update a value in the model the rendered html is automatically updated without your interference. Quick example of how you could use it here...
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
<script>
function PlayerModel() {
// the player score
this.playerGold = ko.observable(0);
// The increase gold function to add 1 to the player score
this.increaseGold = function() {
var oldScore = parseInt(this.playerGold());
this.playerGold(++oldScore);
};
}
var model = new PlayerModel();
$( document ).ready(function() {
ko.applyBindings(model);
});
</script>
</head>
<body>Gold : <strong data-bind="text: playerGold"></strong></li>
<button onclick="javascript:model.increaseGold()">Standard JS - Increase gold</button>
<button data-bind="click: increaseGold">KO Data bound -Increase gold</button>
</body>
</html>
Its as easy as that. You can add more variables easily to your player model then if you want. I like this approach because it keeps things easy but also affords you a lot of control over the implementation etc. Ember is another great alternative though.

Grails rendered content accessing id elements dynamically

AJAX content is being rendered with a remoteLink function inside the form to populate a accordion (just a little background info).
The function attatchEmail(test) which is being called on the double-click of each paragraph content of the JQuery Accordion widget. This is what happens running the function... Screenshot of 1st alert & Screenshot of 2nd alert.
Is it not possible to select the paragraph and get the contents from the paragraph like below?
(I have tried changing .val to .html and .text. I have also tried $('#'+testingID))
_form.GSP
function attatchEmail(test) {
$(document).ready(function()
{
var testingID = test.id;
alert(testingID);
var testingValue = $(testingID).val();
alert(testingValue);
});
};
_contactListAjax.GSP
<g:each in="${contactList}" status = "i" var="contact">
<h3>${contact.contactSurname +', '+ contact.contactForename}</h3>
<div><p id="contact${contact.id}" ondblclick="attatchEmail(this)">${'Email: '+contact.email}</p></div>
</g:each>
Run out of avenues to explore, I'm sure I've done something simple like this before perfectly fine :/
See two screenshots please for better insight, thanks
Well, it looks like you're using jQuery but it also looks like you're not really buying into the jQuery methodology. Mixing behavior with markup is not really considered a good practice these days, especially when using a library like jQuery. I'm not sure of your exact issue but I would recommend changing it to something like the following:
<g:each in="${contactList}" status = "i" var="contact">
<h3>${contact.contactSurname +', '+ contact.contactForename}</h3>
<div><p class="contact-email" data-id="${contact.id}">${'Email: '+contact.email}</p></div>
</g:each>
$(function() {
$("body").on("dblclick", ".contact-email", attachEmail);
});
function attatchEmail(event) {
var $element = $(event.target);
var id = $element.data("id");
};
This should help fix any issues with dynamic rendering because of the way the jQuery on function works.

Categories