How to correctly append dynamic GetUIKit accordions? - javascript

I'm trying to dynamically append UIKit Accordions into a sortable list. The initial items (accordions) are working, but the dynamically appended is not working.
HTML
<div class="second-list" data-uk-observe>
<div class="uk-sortable uk-margin uk-accordion" data-uk-sortable="{group:'test'}" data-uk-accordion="{showfirst: false}">
<div class="uk-margin">
<div class="uk-panel uk-panel-box uk-accordion-title">Item 1
<button class="uk-button delete-btn">×</button>
</div>
<div class="uk-accordion-content">test1</div>
</div>
<div class="uk-margin">
<div class="uk-panel uk-panel-box uk-accordion-title">Item 2
<button class="uk-button delete-btn">×</button>
</div>
<div class="uk-accordion-content">test2</div>
</div>
</div>
</div>
JavaScript
// Remove item handler
$(".delete-btn").on("click", function () {
// 400 is default
$(this).closest(".uk-margin").fadeOut(400, function () {
$(this).remove();
});
return false;
});
function addItem () {
var $container = $(".second-list").find("[data-uk-sortable]");
$container.append(
`<div class="uk-margin">
<div class="uk-panel uk-panel-box uk-accordion-title">new item
<button class="uk-button delete-btn">×</button>
</div>
<div class="uk-accordion-content">description</div>
</div>`
);
}
addItem();
This is the minimal example I created to reproduce the problem. The sortable dynamic item is working fine (can be dragged), but the accordion doesn't. When clicking it, I'm getting:
Uncaught TypeError: Cannot read property 'data' of undefined
What I have tried:
Using data-uk-observe in the sortable element. I don't feel any difference using it.
Trying to initialize the accordion using the UIKit API:
UIkit.accordion($(".uk-margin"));
UIkit.accordion($(".uk-accordion-title"));
UIkit.accordion($(".uk-accordion-content"));
None of these doesn't fixe the problem.
So, how to correctly append dynamic GetUIKit accordions?
JSFIDDLE

It looks like what you want to do is:
Omit the data-uk-accordion attribute.
Save the object returned from calling UIkit.accordion(element, options).
After new accordion child elements have been added, call accordion.update(). (assuming you saved the returned object above in a variable called accordion)
For more information about how I arrived at that, check out the related issue on GitHub.
(also posted as an answer on UIKit accordion and ng-repeat doesn't work)

Try removing the accordion data from the element before you reinitialize it:
$(".uk-margin").removeData("accordion");
UIkit.accordion($(".uk-margin"));
That worked for me when I was writing an angular directive for this.

try update all items of accordion after add,
var component = UIkit.accordion($('.uk-accordion'));
component.update();
That worked for me.

I had the same issue but I'm using Meteor. This took me a good hour to get worked out, and I tried several different solutions, including using Template.onRender, Template.onCreated, but to no avail. They all seemed to attempt to initialize the UIKit accordion JS too soon.
I probably should've known better, but the right answer was to put #codermonkeyfuel's code before the end of my template helper, like so:
Template.appsList.helpers({
myApps: function() {
if (Meteor.user() ) {
console.log("we have a user: " + Meteor.user() );
var userId = Meteor.userId();
var user = Meteor.users.findOne(Meteor.userId());
console.log("userId: " + userId);
var apps = Meteor.users.findOne({_id: userId}, {
fields: {
myApps: 1
}
}).myApps;
// console.log(myApps);
return user && apps;
}
setTimeout(function() {
var accordion = UIkit.accordion($('.uk-accordion'), {collapse: false});
accordion.update();
}, 1000)
}
});
My head was thinking it was a timing issue with the rendering. In retrospect, the actual solution makes perfect sense. Hope it's useful for anyone using UIKit with MeteorJS.
meteor javascript uikit

Related

How can we increment the Semantic UI Progress bar based on the mongoDB data?

I have a situation where the progress of a job should be displayed on the UI, for that I'm constantly(5 sec) retrieving the job progress and storing into mongoDB. As Semantic UI provide progress bar functionality, I tried implementing in my meteor project. The problem is that progress is not getting incremented.
sample.html
<div class="ui blue active progress stats" style="padding:0.25%;;width:7%;margin:0% 1%;margin-top:0.5%;" data-value={{prog}} id="statProgress">
<div class="bar">
<div class="progress {{progValue}}"></div>
</div>
</div>
sample.js
$('#statProgress')
.progress({
label: 'ratio',
text: {
ratio: '{value}'
}
});
Template.sample.onRendered (function(){
var progv=Session.get("selectedProgress");
this.$('.ui.progress').progress({value: progv});
});
Template.sample.helpers({
'progValue':function(){
var id=this._id; //job ID
console.log("inside the progValue and the id is: ",id);
var jobDetails=job.find({_id:id}).fetch();
console.log(jobDetails);
console.log(jobDetails[0].prog);
Session.set("selectedProgress",jobDetails[0].prog);
var x=Session.get("selectedProgress");
console.log(x);
}
});
Can anyone point where exactly I have missed out and how can i correct it?
Several things to double check:
Semantic UI initialisation: Your don't need to set a value here as your value will be provided by your helper
Template.sample.onRendered (function(){
var progv=Session.get("selectedProgress");
this.$('.ui.progress').progress();
});
Semantic UI usage (I removed your style for simplicity): If you use data-value to get the value of the Blaze helper, you don't need to add the value again in the inner div.
<div class="ui blue active progress stats" data-value={{progValue}} id="statProgress">
<div class="bar">
<div class="progress"></div>
</div>
</div>
Blaze Helper: Your helper should return a value ! If your last statement is a console.log(..), the return value will be 'undefined'. You don't need the Session as the Mongo find is also reactive and will re-run on every update (By the way, another suggestion could be to query your collection with 'findOne' instead of find().fetch() and your helper could take a single line):
'progValue':function(){
var id=this._id; //job ID
var jobDetails=job.find({_id:id}).fetch();
return(jobDetails[0].prog);
}
Good luck
JF

Fastest way to template and append elements from array

Using jQuery and Javascript, I am building a chatbox from an array of messages. My current setup is something similar to this:
HTML:
<div id="messageTemplate">
<div class="messageContainer">
<div class="chatMessage"></div>
<div class="chatTime"></div>
<div class="chatActions">
<span class="chatAction deleteMessage">Delete</span>
</div>
</div>
</div>
Javascript:
var template=$('#messageTemplate');
var chatbox=$('#chatbox');
$.each(messageArr,function(index,messageObject) {
var newMessage=$(template.html()); //Make a new DOM
newMessage.find('div.chatMessage').text(messageObject.message);
newMessage.find('div.chatTime').text(messageObject.time);
newMessage.find('div.chatAction.deleteMessage').click(function() {
//Delete message Code
});
//Append newMessage to chatbox
newMessage.appendTo(chatbox);
});
This code works, but after reading this article I found out this is not efficient at all. With 100+ chat messages this starts to slow down.
What's the best way to be doing this? Not looking for code to be written for me, but just a general guide on the best method to template, build the html, append, and add click handlers?

Meteor & JCrop: Issue trying to replicate a JCrop example

When I installed JCrop and tried to test it I got the JCrop pointer showing but it shows across the whole page instead of just over the image. Also when selecting an area on the image you can't click and drag, the picture darkens just like the example at the link below but that's all. It's not possible to select an area using my code. Can't see anything I've done wrong.
This is what I'm trying to achieve (just to get started):
http://deepliquid.com/projects/Jcrop/demos/tutorial1.html
This is my template:
<template name="home">
<div class="panel-body">
<p>Home content here</p>
<img id="target" src="forrest.jpg" />
</div>
</template>
The callback function to call when the template is rendered:
Template.home.rendered = function () {
jQuery(function(){
jQuery('#target').Jcrop({
trackDocument: true
});
});
}
Anyone got any ideas on this one?
Thanks again :)
Looks like a missing semi colon was the issue. Code should be:
Template.home.rendered = function () {
jQuery(function(){
jQuery('#target').Jcrop({
trackDocument: true
});
});
};

updating div with jQuery and Knockout.js with .html() not working

This should be a simple matter of updating some simple modal controls with .html() but for some reason, I'm having issues. This is the modal code...
<div id="answerTaskQuestionModal" class=" modal-dialog" data-bind="with: currentQuestion">
<div id="answerTaskQuestionValidation" class="validation"></div>
<span data-bind="text: html"></span>
<div id="taskQuestionAnswer"></div>
</div>
And here is the JavaScript inside my working view model...
self.answerTaskQuestion = function (question) {
$('#answerTaskQuestionValidation').html('');
var $taskQuestionAnswer = $('#taskQuestionAnswer');
$taskQuestionAnswer.html(' \* {my html with bindings} *\ ');
$answerTaskQuestionModal.dialog('open');
self.currentQuestion(question);
};
Basically, I'm trying to dynamically change the ways one can answer a question as a proof of concept. If I just paste the html inside the target div, they work. However, when I check the value of .html(), this is what happens...
first run: $taskQuestionAnswer.html() returns undefined
second run: $taskQuestionAnswer.html() returns the proper HTML but the div won't update.
Replacing the bindings with just simple HTML doesn't help either. What am I missing here?
I think after $taskQuestionAnswer.html(' \* {my html with bindings} *\ ');
you should call ko.applyBindings(myViewModel) again to apply view model to new html.

Observables in Angularjs

I'm doing few exercises to understand how Angularjs work... but I'm a bit confused at the moment...
Following the API, various documentation and tutorials I cannot find exactly what I would like to see...
So I created a small JsFiddle: http://jsfiddle.net/8HqnZ/
What I'm doing is really basic... and probably I'm also doing in a bad way... but I'm learning and every tips will be fantastic for me.
My target here is:
Make everything dynamic... obviously.
I don't understand why if I change name or date on my inputs on top my red bars do not update (seems like it isn't observable...)
I also created a get data button to see my updated Json but it return just [object, Object]...
In plus after I understand these two things I would like to make it inverse as well... I mean something like a draggable red bars that will update date on top... (if it is possible).
Here is my small app:
function App($scope) {
$scope.windows = [
{"name":"First Window","from":"2013-11-05","to":"2013-11-21"},
{"name":"Second","from":"2013-11-10","to":"2013-11-30"},
{"name":"Another One","from":"2013-11-17","to":"2013-11-20"}
];
$scope.addWindow = function() {
$scope.windows.push({"name":"insert name","from":"2013-11-01","to":"2013-11-02"});
};
$scope.setWindow = function(from, to) {
var f = (from.split("-")[2]) * 40,
t = ((to.split("-")[2]) * 40) - f;
return { f: f, t: t };
};
$scope.getData = function() {
console.log($scope.windows);
};
};
The HTML looks like this (I cutted off the "calendar"):
<div ng-app ng-controller="App">
<section id="window-data">
<div ng-repeat="window in windows">
<label>Name:<input value="{{window.name}}"></label> <label>From:<input type="date" value="{{window.from}}"></label> <label>To:<input type="date" value="{{window.to}}"></label>
</div>
<button id="add-window" ng-click="addWindow()">Add Window</button>
</section>
<section id="window-display">
<div id="date-labels">
<div class="block">
<span class="rotate">2013-11-01</span>
</div>
<div class="block">
<span class="rotate">2013-11-02</span>
</div>
...
</div>
<div id="windows">
<div class="window-container" ng-repeat="window in windows">
<span class="window" style="left:{{setWindow(window.from, window.to).f}}px; width:{{setWindow(window.from, window.to).t}}px">{{window.name}}</span>
</div>
</div>
</section>
<button id="get-data" ng-click="getData()">Get Data</button>
</div>
Please if you know good websites with easy and deep documentation, examples, etc... share it with me.
I've always just used the Angular site for documentation. Have you gone through their tutorial?
For your issues: You'll want to use ng-model on those inputs instead of setting the value.
<input ng-model="window.name">
The other issue occurred because you are trying to console.log JSON. You'll need to turn it into a string to log it:
console.log(JSON.stringify($scope.windows));
http://jsfiddle.net/8HqnZ/1/
1.
I don't understand why if I change name or date on my inputs on top
my red bars do not update (seems like it isn't observable...)
To do 2 way data binding you need to use ng-model
Specifically you need to do this
`<input ng-model="window.name">`
instead of input value as "window.name"
I also created a get data button to see my updated Json but it return
just [object, Object]...
This is as expected.
For a draggable, you need to create a custom angular js directive.

Categories

Resources