I would like to integrate a date picker in a form. So I created a custom DateTimePickerView like this :
App.DateTimePickerView = Em.View.extend
templateName: 'datetimepicker'
didInsertElement: ->
self = this
onChangeDate = (ev) ->
self.set "value", moment.utc(ev.date).format("dd/MM/yyyy hh:mm")
#$('.datetimepicker').datetimepicker(language: 'fr', format: 'dd/mm/yyyy hh:ii').on "changeDate", onChangeDate
Here is the template :
<script type="text/x-handlebars" data-template-name="datetimepicker" >
<input type="text" class="datetimepicker" readonly>
</script>
In my form I want to bind this component to an attribute of my model (I am using the RestAdapter) :
<script type="text/x-handlebars" id="post/_edit">
<p>{{view Ember.TextField valueBinding='title'}}</p>
<p>{{view App.DateTimePickerView valueBinding='date'}}</p>
</script>
Everything works fine in apparence : the DateTimePicker is well displayed and the value is set inside the input.
But there is a problem in the effective binding : when I send the form, the post param "date" (corresponding to the attribute) is null.
When I look inside the generated html code I can see the following :
<p>
<input id="ember393" class="ember-view ember-text-field" type="text" value="Event 1">
</p>
<div id="ember403" class="ember-view">
<input type="text" class="datetimepicker" readonly="">
</div>
I am not an expert in the global ember structure, but I guess that the id element is important for the binding. In that case, for my component, the ember id is put to the container of my component and not to the input containing the value. So I guess the problem is here.
So what could be the correct way to make it work ?
I just created a working jsfiddle here ; we can see that the modifications in the title field are taken into account but not the modifications in the DateTimePickerView component.
I guess the problem lies in the fact that you where trying to listen on an event fired from the datetimepicker which is not captured, and thus the model value not set.
To make things more solid you should get the datetimepicker current date value in your doneEditing function, just before saving the model back to the store.
Let me show in code what I mean:
window.App.EventController = Ember.ObjectController.extend(
...
doneEditing: ->
// relevant code line
#get("model").set("date_begin", $('.datetimepicker').data('date'))
#set "isEditing", false
#get("store").commit()
...
)
And here your (working) jsfiddle.
Hope it helps
Edit
After reading your comment I've modified the input field inside your datetimepicker template. Please see here an updated jsfiddle that also initializes the input field of the datetimepicker on edit begin when calling edit.
...
edit: ->
#set "isEditing", true
startDate = #get("model").get("date_begin")
#$(".datetimepicker").data({date: startDate}).datetimepicker("update")
...
You are now safe to remove the onDateChange function and do init and save inside your edit and doneEditing respectively, applying format or whatever.
Edit 2
Reading your last comment, this is how you register customEvents for example in your App.DateTimePickerView:
...
customEvents: {
changedate: "changeDate"
}
...
this way Ember will be aware of your custom events. You can register whatever events you want but notice that the keyname is lowercased and the value must have the event name to listen to camelcased. For more infos on custom events see here.
Please see here for another update jsfiddle with the changeDate custom event registered.
I have finally resolved this problem making some controls when using the moment.js library.
Everything was working fine with the binding process of the custom datetimepickerview.
Here is a working jsfiddle : here
The relevant code is here :
window.App.DateTimePickerView = Ember.View.extend(
templateName: 'datetimepicker'
didInsertElement: ->
#this test is important and was the problem
if #.get 'value'
#$('input').val moment.utc(#.get 'value').format('LLL')
onChangeDate = (ev) =>
date = moment.utc(ev.date).format('LLL')
#.set "value", date
#$('.datetimepicker').datetimepicker(format: 'dd/MM/yyyy', pickTime: false).on "changeDate", onChangeDate
)
Related
I need to set a variable or array in meteor JS which whenever changes. Wherever it is used on the page changes.
So far I have tried to set values in session.
let in = Session.get("in");
and this in HTML. The following works fine. This changes whenever it detects a change in array
{{#each in}}
<span class="selectable-tags"> {{this}} </span>
{{/each}}
But whenever I try to add these tags to other div using following. Then the ones added to other div does not change.
"click .selectable-tags"(e, t) {
// sets the tags inside the Method box on click
var el = e.target.cloneNode(true);
el.setAttribute('contenteditable', false);
document.querySelector('[contenteditable]').appendChild(el); },
using meteor with blaze UI. This can be used as reference link
Edit: Session.get or set is given for reference . This was to tell that these values are changing as they on any event triggered wherever set.
You need to add a helper that returns the session variable and show the helper in your html code :
Template.yourtemplate.helpers({
inHelper: ()=> {
return Session.get('in');
}
)}
And in html :
<div>{{inHelper}}</div>
Every modification on in by Session.set('in', newValue) will change your HTML.
I have a master and a child component. The child component persists the data for the create mode as well as the edit mode. The child has a data section as follows which is being used when the component is in create mode
data() {
return {
title: '',
description: '',
organizer: '',
startdate: '',
enddate: '',
email: '',
phone: ''
}
},
and my inputs in create mode are as follows
<input type="text" placeholder="enter event title here" class="form-control" v-model="title">
In the edit mode, I am updating a prop value on the client as follows, which is
props:['currentevent']
The value of the currentevent is being passed from the master component to the child component and is also the value that is currently being edited.
so, the complete code for handling an input value looks like as follows
<input type="text" placeholder="enter event title here" class="form-control" v-if="currentevent" :value="currentevent.title">
<input type="text" placeholder="enter event title here" class="form-control" v-else v-model="title">
and in my save method (in the child component), I am checking if currentevent is empty or not. If it is empty then I trigger the add code otherwise, I trigger the update code.
Question : This works , but I have a large form and having to do this for each and every component is not a clean design . Can you please let me know what should I be doing ?
I totally appreciate your predicament. The best way to handle form data is to make it create/update agnostic. Here's what I'd recommend you try:
Instead of maintaining all the data fields as disparate properties, contain them in a single object, in this case I'm calling it eventObj for clarity:
data () {
return {
eventObj: {}
}
}
Then in your markup you'd reference them via the object:
<input type="text" placeholder="..." class="form-control" v-model="eventObj.title">
You'd then need to define a prop for passing in the data (as an object) from the parent component if you are editing:
props: {
currentevent: Object
}
And then you'd just need to map the incoming prop to the child component's data:
created() {
Object.assign(this.eventObj, this.currentevent || {})
}
Now when your inputs like <input v-model="eventObj.title"> are processed, if there is a saved title (that was passed in with currentevent) the field will be prepopulated with it, otherwise it will be blank.
I think this should help you in the right direction toward solving the complexity you're trying to figure out. There are other logistical issues involved with this kind of stuff in general, but I won't drone on. :)
The issue I see is you want to remove the v-if/else in the form. I will recommend here is keep your local data of child to be in sync with the props passed and only use local variable in the form.
One way to do this can be put a watcher on props and whenever props changes, update local variables and only use those variables in form.
watch: {
currentevent: function(newVal){
title = newVal.title,\
description = newVal.description
...
}
}
I'm struggling with an issue that I will explain giving a simple demo.
There's following very simple document in People Collection.
{
"_id" : "vxmLRndHgNocZouJg",
"fname" : "John" ,
"nicks" : [ "Johnny" , "Jo"]
}
Now let's consider following templates. Basically I display username and a list of nicknames with input field for adding more nicknames.
<head>
<title>test</title>
</head>
<body>
{{> name}}<br/>
{{> nicks}}
</body>
<template name="name">
<input type="text" value="{{fname}}"/>
</template>
<template name="nicks">
{{#each nicks}}
<div>{{this}}</div>
{{else}}
no nicks yet
{{/each}}
<input type="text" name="nicks"/>
<input type="submit"/>
</template>
My client javascript code is as follows:
Template.name.fname = function() {
return People.findOne({"fname" : "John"},{
transform : function(doc) {
return doc.fname;
}
});
}
Template.name.rendered = function() {
console.log('Template "name" rendered!');
}
Template.nicks.nicks = function() {
var john = People.findOne({"fname" : "John"});
if(john) return john.nicks;
}
Template.nicks.events({
'click input[type="submit"]' : function () {
var johnId = People.findOne({"fname" : "John"})._id; // demo code
People.update(johnId,{
$addToSet : {
nicks : $('input[name="nicks"]').val()
}
})
}
});
My problem is that after adding nickname (update of nicks field in a document) template name is re-rendered (I know because I console.log it). When I query People collection to provide data for name template I use transform option so changes in nicks field shouldn't have impact on name template.
Meteor docs supports this:
Cursors are a reactive data source. The first time you retrieve a cursor's documents with fetch, map, or forEach inside a reactive computation (eg, a template or autorun), Meteor will register a dependency on the underlying data. Any change to the collection that changes the documents in a cursor will trigger a recomputation.
Why template name is re-rendered then?
The template is re-rendered because you change the People collection.
When you alter the People collection, Meteor automatically assumes that everything that it provides data to needs to be recalculated. (Which your name template does via Template.name.fname.
Even though you transform the output of the cursor, the People collection has changed in some way. The query is done before the transform is used, in other words, its not the transform that is looked at but the whole collection.
Meteor thinks that perhaps your document with {'fname':'John'} may have some other field that might have changed and it needs to requery it to check (which the nicks field has been altered). The transform is then applied after the requery.
Your HTML might not actually change at this point, only if the cursor returns something different will the html be changed.
If it becomes an issue in any scenario (i.e forms being cleared or DOM being changed when it shouldn't be) you can use the {{#isolate}} {{/isolate}} blocks to ensure that only everything inside them is re-rendered and nothing outside.
I'm building a Durandal app, and the view I'm currently working on has two <select> boxes. I've got both of them bound to a ko.observableArray and their value to another ko.observable as follows:
<select data-bind="options: dateOptions, optionsText: 'display', value: selectedDate></select>
<select data-bind="options: buyerOptions, optionsText: 'display', value: slectedBuyer"></select>
The second one is dependent on the value of the first one, so I'm populating them at different times. For the first, I'm querying my data source during the activate() call and then passing the data to a separate method to populate the array the data (in the form of simple JS objects) when the promise returned by the request is resolved:
var populateDateOptions = function(dates) {
$.each(dates, function() {
dateOptions.push({
display: dateToString(this.pbDateOpt),
date: this.pbDateOpt
});
});
};
That works fine - the <select> has values ready for me when the view is rendered. But, after that, I can't get either <select> to respond to changes in their respective observable arrays. The next <select> is populated in a nearly-identical fashion once a value is selected in the first <select>, and I can verify that the buyerOptions array is indeed being populated, but the <select> doesn't change. I also tried adding a value to the first <select> by pushing an object into its array via dev tools and get the same result: the array is updated, but the UI doesn't change.
I've used the "options" binding in several other apps and never had this issue before, but this is my first Durandal app so I'm wondering if maybe there's something I'm missing?
Thanks!
Update
I added some more bound elements to the view and none of them are working, so there must be something weird going on with the composer. Not sure where to start looking for an issue (the viewmodel and view are very similar in structure to another pair that is working fine). Any tips?
Just as a reference, this isn't a Durandal issue - this is a Knockout issue.
Also, a way that I have found most efficient to do this is the following the same way you have it -
<select data-bind="options: dateOptions, optionsText: 'display', value: selectedDate></select>
<select data-bind="options: buyerOptions, optionsText: 'display', value: selectedBuyer"></select>
but in your view model make the buyerOptions dependent directly on the dateOptions like so -
var buyerOptions = ko.computed(function () {
var opts = ko.observableArray();
if (!selectedDate()) { opts.push(display: '<Select a Date>'); }
else { opts(getBuyersOptions(selectedDate().id()); }
return opts;
});
This way if your selectedDate observable is empty (one hasn't been selected) then no buyerOptions appear, but if you select a date it will populate it based off some value in selectedDate, like Id. It will also automatically update whenever a new date is chosen, without you having to explicitly tell it to with JavaScript or w/e
Turning on Durandal's debug mode by setting system.debug(true) in main.js helped me discover some code errors that weren't presenting themselves via console warnings. With those resolved, everything bound/worked correctly.
Lesson learned - leave debug mode on when you're in development!
In a asp.net C# webapp I'm using the CKEditor 3.6.2 and I'm facing the following problem:
In my stylesheet I have a CSS class to use in tables and I'm trying to bring this class already filled in the "Table properties", "Advanced" tab and the "Stylesheet Classes" field.
I want to bring this field filled with the string "blue_table", which is the name of my CSS class. I'm working with the source of the "table" plugin. I have figured out how to change the value of fields like width and height, but the one I want is the "Stylesheet Classes" field.
Do any of you know to to set a default value for this field?
You don't have to edit the ckeditor.js file to customise the editor. You can add the following either to config.js and use it site wide or on any page where you're using CKEditor (inside a script tag as below, after the editor fields you're using).
<script type="text/javascript">
CKEDITOR.on( 'dialogDefinition', function( ev ) {
// Take the dialog name and its definition from the event data.
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
// Check if the definition is from the dialog we're
// interested on (the Table dialog).
if ( dialogName == 'table' ) {
// Set the tab
var advTab = dialogDefinition.getContents( 'advanced');
// Grab the field
var stylesField = advTab.get('advCSSClasses');
// Set the default value
stylesField['default'] = 'blue_table';
}
});
</script>
This is modified from the CKEditor documentation. The hardest part is working out the IDs and names for all the fields used in the dialogs.
Finally I found the answer. This property is in the dialogadvtab, in the property "advCSSClasses". The thing is that this plugin is inside the core js, I mean the ckeditor.js.
I had to do this :
children :
[
{
id : 'advCSSClasses',
att : 'class',
type : 'text',
label : lang.cssClasses,
'default' : 'blue_table',
setup : setupAdvParams,
commit : commitAdvParams
}
]
The "problem" now is that I had to do it in the ckeditor.js, which is not a good practice. The problem is solved, but not int the best way.