Facing Trouble in using Bootstrap3 datetimepicker in backbonejs - backbone.js

Html-template with bootstrap responsive.
<div class="row">
<div class="col-lg-2"><label class="al-right">Start Time :</label>
</div>
<div class="col-lg-2">
<input type="text" data-name="startTime" id="timeinput1" class="form-control">
</div>
Getting the id from here and based on this timeinput1 id and calling the mouseover event in backbone view
Backbone view:
var ItView = Backbone.TemplateView.extend({
templateName : "itTempl",
initialize : function(options) {
Backbone.View.prototype.initialize.call(this, options);
//default function call
this.goToGridView();
},
events : {
/* For only Datepicker events*/
'mouseover #dateinput1' : 'createDatePicker',
'mouseover #dateinput2' : 'createDatePicker',
/* For Datetimepicker events not working*/
'mouseover #timeinput1' : 'datetimepicker'
},
// this is how i am using datetimepicker() function of bootstrap3
datetimepicker:function(e) {
var view = this;
$(e.currentTarget).datetimepicker();
},
Using ModelBinder for Backbone:
Data which has come with datetimepicker() is not populated into the backbone models where as data which comes from datepicker() and timepicker is poupulating into backbone models.
kindly help me about this issue.

Related

Bootstrap DateTimpicker Angular Binding doesn't update after selection in calenderdialog

I have a problem with the model binding of my bootstrap datetimepicker, that doesn't update after selecting a date in the dialog.
When I directly edit the input field the binding gets triggered, but selecting doesn't update the binding.
I have a small
Plunker example
<body ng-controller="MainCtrl">
<p>Hello {{name}}! {{datum}}</p>
<div class="input-group">
<span class="input-group-addon add-on"><span class="fa fa-calendar"></span></span>
<input type="text" class="form-control datetimepicker" ng-model="datum"/>
</div>
</body>
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.datum = new Date();
if($(".datetimepicker").length > 0){
$('.datetimepicker').datetimepicker({
format: 'YYYY-MM-DD HH:mm'
});
}
});
Plain bootstrap doesn't work with angular. You will need/should use a bootstrap-angular binding library instead of the bootstrap scripts. You still use the bootstrap css/sass/less etc. Angularstrap is one such library and it doesn't depend on jquery.
When you use angularstraps datepicker it will update your binding.
The (foul, hideous, messy) alternative is to bind an event handler to the bootstrap datepicker change event and from within there call $scope.digest() and/or trigger a changed event manually on the textfield element.

access an element inside ng-repeat when dynamic html loaded

I am trying to access an DOM element inside a dymanic loaded HTML with http get request. The code that I am using inside controller is
$http.get("/ProjectManager/Edit?id=" + requestId).success(function (data, status, headers, config) {
data = data.trim();
var newDirective = angular.element(data);
angular.element(document.getElementById("editDiv")).html(newDirective);
$compile(newDirective)($scope);
var resources = angular.element(document.getElementById("projectResources")).val();
for (var i = 0; i < resources.length; i++) {
var resourceData = new ProjectResourcesModel(resources[i].ResourceID, resources[i].ProjectResourceID, resources[i].Employee, resources[i].IsApprover, resources[i].StartDate,
resources[i].EndDate)
$scope.resource.push(resourceData);
//$scope.$apply();
var id = "startDate" + resources[i].ResourceID;
angular.element(document.getElementById(id)).datetimepicker({
defaultDate: resources[i].StartDate,
format: 'MM/DD/YYYY',
})
}
})
I am trying to access a element with particular id that is present in my array element.
View HTML inside a ng-repeat is as follows
<div>
<div class="form-group">
<div class='input-group date' id='startDate{{item.ResourceID}}'>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
<input ng-model="item.StartDate" type='text' id="txtStartDate{{item.ResourceID}}" class="form-control" />
</div>
</div>
</div>
</div>
I have to attach bootstrap datetimepicker to a textbox so I want to access a div inside ng-repeat whose ID is present inside by ng-repeat array.
But when I access the item with that id inside success of get request I am not getting the element. for e.g id of div would be startDate151 after the view binding.
So I tried using $scope.$apply() with which I am able attach the datepicker to element inside ng-repeat but I started getting a console error
Error: [$rootScope:inprog] $digest already in progress
Can anyone help me to resolve this or can I use some other alternative in this situation.

ngRepeat not updating after model changed

I'm tring to code a little search input to get data from a database using ngResource.
the data are shown in the page with a ng-repeat, but when i do the search and the $scope has been updated, the view is not updated and show old data.
Here is the code:
main.html (active view)
<div ng-controller="searchCtrl as searchCtrl" layout="column">
<form class="form-inline search-form col-md-offset-1">
<div class="form-group col-md-5">
<label class="sr-only" for="search_location">Location</label> <input
id="search_location" type="search" class="form-control"
ng-Autocomplete ng-model="place" placeholder="Location" />
</div>
<div class="form-group col-md-5">
<label class="sr-only" for="search_tags">Tags</label> <input
style="width: 100%;" id="search_tags" type="search"
class="form-control" id="search_tags" placeholder="Tags">
</div>
<div class="col-md-1">
<md-button class="md-fab md-mini" aria-label="Search" ng-click="searchCtrl.search()"> <md-icon class="md-fab-center"
md-font-icon="glyphicon glyphicon-search" style="color: black;"></md-icon>
</md-button>
</div>
</form>
</div>
<div ng-controller="mainCtrl">
<div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>
</div>
main.js
'use strict';
app.factory('Eventi', function($resource) {
return $resource('/eventsws/events/:location', {location : '#location'}, {
search: {
method: 'GET',
params: {
'location' : "#location"
},
isArray : true
}
})
});
app.controller('mainCtrl', function($scope, Eventi) {
$scope.eventi = Eventi.query();
});
searchbar.js
'use strict';
app.controller('searchCtrl', function($scope, Eventi) {
$scope.place = null;
this.search = function() {
$scope.eventi = Eventi.search({
'location' : $scope.place
});
}
});
when it start it get all the data from the database and display them correctly, when i try to make a search, the $scope.eventi is updated (i can see the new data in $scope.eventi from the debug) but the view still show the old data and never update.
I've tried to use $scope.$apply at the end of the search function but the result is the same.
Have you any idea why it's not working?
Thanks for your time.
The $scope.eventi you see in the debug is the one in your searchCtrl and not the one from your mainCtrl. To update your mainCtrl $scope.eventi you have to find an other way.
A clean but long solution would be using services to shares variables in your controllers.
To answer the question in comments :
i can see it updated, but the view still show the old data
I guess what's the problem (even if i actually didn't see your code).
Problem
If you bind your var like this :
Service
[...]
service.serviceVar = 1;
return service
[...]
This will create a "1" var with a reference.
Controller
[...]
$scope.myvar = Service.serviceVar;
[...]
This will bind $scope.myvar to the "1" reference.
If you do this in your service or in an other controller :
service.serviceVar = 2;
You will create a new var "2" with a new reference and you will assign this reference to service.serviceVar. Badly all your old references to the old 1 var will not update.
Solution
To avoid that do it like this :
Service
[...]
service.servicevar = {};
service.servicevar.value = 1;
return service
[...]
You create an object with a new reference and assign it to servicevar.
You create a var "1" and assign it to servicevar.value.
Controller
[...]
$scope.myvar = Service.servicevar;
[...]
You assign the servicevar reference to your scope var.
view
{{myvar.value}}
You can use the value by using the property of your var.
Updating the var doing this :
service.servicevar.value = 2;
You will create a new var "2" with a new reference and replace the old reference by this one.
BUT this time you keep all your references to servicevar in your controllers.
I hope i was clear and it answer your question.
EDIT :
Try to never ever use $scope.$apply. It's a really bad practice. If you use that to make something works, you should probably find an other to do that (And it will be a great question for Stacks i guess : "Why do i need $apply to solve my problem XXXXX")
rsnorman15 has a good point about your uses of asynchronous calls. Take a look at his answer too.
Here is one of my old plunker using a service to share properties
Just change:
$scope.eventi = Eventi.search({
'location' : $scope.place
});
to
Eventi.search({
'location' : $scope.place
}, function(eventi) {
$scope.eventi = eventi
});
It's an asynchronous call so it must be assigned in the success handler.
Another issue you are running into is your ng-repeat is not contained within the div that searchCtrl is scoped. Update your HTML so that it is contained like so:
<div ng-controller="searchCtrl as searchCtrl" layout="column">
<form class="form-inline search-form col-md-offset-1">
... form stuff
</form>
<div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>
</div>

Kendo UI and angular - no widget in $scope

I'm using Kendo UI version 2014.2.716 with AngularJS version 1.2.27, and I made a grid using a directive
<div ng-controller="MyController as ctrl">
<div id="myGrid" kendo-grid k-options="{some options}"></div>
<button ng-click="ctrl.doSomething()"></div>
</div>
I read that if you give a name to the grid (like this: kendo-grid="myGridOnScope"), you can access the widget in the controller scope in this way:
myModule.controller('MyController', function($scope) {
this.doSomething = function() {
console.log($scope.myGridOnScope);
}
}
The console.log should log a widget object, but in my case it's undefined. What am I doing wrong? Thanks for the help
I have found out the problem myself, so I'm going to post an answer if someone has the same problem. If you use the controllerAs syntax in AngularJS, you can't just write the name of the widget - you have to prefix it with your controller alias.
Take a look at this example:
<div ng-controller="MyController as ctrl">
<div kendo-grid="myGridName"></div>
</div>
This will not give you the grid object on the $scope - for that you need to add the ctrl prefix:
<div ng-controller="MyController as ctrl">
<div kendo-grid="ctrl.myGridName"></div>
</div>
Now you have access to the widget in your controller like this:
angular.module('MyModule',['kendo.directives'])
.controller('MyController', function($scope){
// this gives you the widget object
console.log(this.myGridName);
// however, this doesn't work
console.log($scope.myGridName);
});
I hope I helped someone with this post.
Cheers,
Try waiting for the event that Kendo emits.
Html
<div kendo-grid="grid" options="gridOptions"></div>
Javascript
$scope.$on("kendoWidgetCreated", function(event, widget){
if (widget === $scope.grid) {
console.log($scope.grid);
}
});
Edit: See this Plunker
It is because angular is too fast and the kendo element doesn't exist when you try to set the options.
I solved this with a watch.
This is my html code:
<div kendo-grid="ListDesign"></div>
And this is my angular code
$scope.$watch('ListDesign', function () {
if ($scope.ListDesign != undefined) {
var gridOptions = {
columns: columns,
sortable: {
mode: 'multiple',
allowUnsort: true
}
};
$scope.ListDesign.setOptions(gridOptions);
$scope.ListDesign.setDataSource(dataSource);
}
});
Does this answer your question?

How to use backbone with mustache and an unknown number of views?

I'm using mustache to render a series of images. Each image is accompanied by a text input for setting the image's caption, an update button for updating the caption in the database via Ajax, and a delete button for deleting the image from the database (also via Ajax):
{{#logos}}
<div class="logo">
<div class="logo-input">
<input type="text" placeholder="Caption" value="{{caption}}" />
</div>
<div class="logo-buttons">
<button>Update</button>
<button>Delete</button>
</div>
</div>
{{/logos}}
I'm new to backbone, and I can't figure out how to "associate" each update/delete button with its corresponding logo/caption. What's the best way to do this, considering that the number of images is unknown at run time?
You have two problems:
How do you know which button is pressed?
How do you know which logo you're working with?
The easiest way to solve the first problem is to attach a class to the buttons:
<button type="button" class="update">Update</button>
<button type="button" class="delete">Delete</button>
Then you can bind the events directly to the buttons using the view's events:
events: {
'click .update': 'update_caption',
'click .delete': 'delete_caption'
}
Also, you should always specify the type attribute when using <button>, the spec says that <button type="button"> is the default but some browsers use <button type="submit"> instead. If you always specify type="button" you don't have to worry about what sort of nonsense the browsers will get up to.
Now you have to figure out which logo you're working with.
One way is to keep using a single view and attach a data attribute somewhere easy to find. For example:
{{#logos}}
<div class="logo" data-logo="{{id}}">
<!-- ... -->
</div>
{{/logos}}
Then you can do things like this in the click handlers:
update_caption: function(ev) {
var id = $(ev.currentTarget).closest('.logo').data('logo');
var logo = this.collection.get(id);
//...
}
Demo: http://jsfiddle.net/ambiguous/DwkPV/
Alternatively, you could use one sub-view for each logo. Here you'd have one view per-logo:
var LogoView = Backbone.View.extend({
className: 'logo',
events: {
'click .update': 'update_caption',
'click .delete': 'delete_caption'
},
//...
});
and a template without the {{#logos}} loop or the outer per-logo <div>:
<div class="logo-input">
<input type="text" placeholder="Caption" value="{{caption}}" />
</div>
<div class="logo-buttons">
<button>Update</button>
<button>Delete</button>
</div>
and the click handlers would simply look at this.model:
update_caption: function() {
var logo = this.model;
//...
}
Then a main view to iterate over the logos and render the subviews:
var LogosView = Backbone.View.extend({
render: function() {
this.collection.each(function(logo) {
var v = new LogoView({ model: logo });
this.$el.append(v.render().el);
}, this);
return this;
},
//...
});
Demo: http://jsfiddle.net/ambiguous/9A756/

Resources