SonataAdmin custom route - sonata-admin

I am trying to display different Events on a calendar in one of my SonataAdmin Entities.
I have 2 services, Practice and Event:
bm.user.admin.practice:
class: BM\UserBundle\Admin\PracticeAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: cvp_users, label: Practice }
arguments: [bm.user.admin.practice, BM\UserBundle\Entity\Practice, BMUserBundle:PracticeAdmin]
and
bm.crm.admin.event:
class: BM\CrmBundle\Admin\EventAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: cvp_users, label: Schedule }
arguments: [bm.crm.admin.event, BM\CrmBundle\Entity\Event, BMCrmBundle:EventAdmin]
The calendar is displayed in the editAction of the Practice
My problem is, I'm trying to get results from an action in the EventAdminController
/**
* Fetch Events based on User.
*
* #Route("/admin-events-create/{id}", name="create_event", options={"expose"=true})
* #Method("GET|POST")
* #Template()
*/
public function fetchEventsAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('BMUserBundle:User')->find($id);
$events = $em->getRepository('BMCrmBundle:Event')->findAllEventsByUser($user->getId());
}
I'm trying to call this using the following:
{{ path('fetch_events', { _sonata_admin: 'bm.crm.admin.events'} ) }}
But that is missing the id that I need to use in the controller.
Changing it to:
{{ path('fetch_events', { id: 'myObj.id', _sonata_admin: 'bm.crm.admin.event'} ) }} or anything similar always gives me:
There is no_sonata_admindefined for the controller
Any ideas on how I can pass the id value I need to the route?
Thanks

First in EventAdmin class
use Sonata\AdminBundle\Route\RouteCollection;
then add method
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('fetch_events', '{id}/fetch_events');
}
You can check declared routes for admin class if you are on *nix system with grep:
php app/console router:debug | grep events
use it as
{{ path('fetch_events', { 'id': object.id } ) }}

I think that error is in path
{{ path('fetch_events', { 'id': object.id } ) }}
Sonata custom route is prefixed with base route name of admin:
{{ path('your_admin_base_route_name_fetch_events', { 'id': object.id } ) }}
short name of custom route can be used for URL generated by admin method
admin.generateUrl('fetch_events', { 'id': object.id } )

Related

Is there a way to open new tab in navigation bar for custom lightning component with record name as tab label?

I need to open the new navigation tab in navigation bar in Lightning Experience in Non Console App environment.Tab should have record name pre-populated as label.
Tried following approach:
Created custom tab for target lightning component
In Source Component:
Created Page Reference with type as standard__navItemPage.
for attributes specified custom tab name for target component.
Using navigation service redirected the control to new URL.
In Target Component:
Using interface isUrlAddressable to retrieve the page param.
var pageReference = {
type: 'standard__navItemPage',
attributes: {
apiName: 'Product_Overview',
},
state: {
c__productId: itemId,
c__isfavourite : isfavourite,
c__isSourceSearchResultCmp : false
}
};
var navService = component.find("navService");
navService.generateUrl(pageReference)
.then($A.getCallback(function(url) {
console.log('Using Navigate'+url);
navService.navigate(pageReference);
}), $A.getCallback(function(error) {
console.log(error);
}));
The issue is , the navigation tab which is getting open is not having details like record name and I could not find any API or methods the same.
Any guidance here would be appreciated.
var pageReference = {
type: 'standard__navItemPage',
attributes: {
apiName: 'Product_Overview',
},
state: {
c__productId: itemId,
c__isfavourite : isfavourite,
c__isSourceSearchResultCmp : false
}};
var navService = component.find("navService");
navService.generateUrl(pageReference).then($A.getCallback(function(url) {
console.log('Using Navigate'+url);
//---add this line which allows you to open url in new tab instead of navService
window.open('https:'+url,
'_blank' // <- This is what makes it open in a new window.
);
}),$A.getCallback(function(error) {
console.log(error);
}));
navigateToRecord(event) {
this[NavigationMixin.GenerateUrl]({
type: 'standard__recordPage',
attributes: {
recordId: event.target.name,
objectApiName: 'Product2',
actionName: 'view',
},
}).then((url) => {
window.open(url);
});
}
If you encounter any issue, please let me know.

Angular-Formly Nested Model Not Updating

I am having an interesting issue with angular-formly. I am attempting to use the 'model' tag as shown below because my model is not flat.
{
'key': 'last',
'model': 'model.name',
'templateOptions: {}
}
However, I cannot update the model in a clean manner. Simply replacing model or even model.name with a matching model that contains the updated value does not cause the model to update the view.
var newModel = {
name: {
first: 'Gandalf',
last: 'The White'
}
};
self.model = {
name: {
first: 'Gandalf',
last: 'The Grey'
}
};
function setNewLastName() {
self.model = newModel;
}
setNewLastName();
However if I drill down to the specific property, it works as expected.
self.model.name.last = self.newModel.name.last;
Here is a link to a JSBin where the value updates using the drill-down method immediately above.
Drill-down JSBin
Another JSBin that attempts to update the model by assigning a new model that does not update.
Assign Model JSBin
Has anyone ran into this issue or can you see where I'm doing something wrong?
You replace the model for each key, therefore you never see the changes.
What you need to do is to match the model in the key itself.
vm.fields = [
{
key: 'name.first', // <-- HERE
type: 'input',
//model: vm.model.name, //Wrong
templateOptions: {
label: 'First Name'
}
},
{
key: 'name.first', // <-- AND HERE
type: 'input',
//model: vm.model.name, //Wrong
templateOptions: {
label: 'Last Name'
}
},
//...
];
See corrected example: http://jsbin.com/pupijoc/1/edit?js,console,output
UPDATE: Nested properties are also handled by fieldGroups
Se updated example: http://jsbin.com/pupijoc/3/edit?js,console,output

Angularjs select elements from list and display in textarea

I have a problem with Angular and nya-select.
Example array in my angular controller:
vm.arrayCollection = [
{ name: 'Alice', mail: 'Class A' },
{ name: 'Bob', mail: 'Class B1' },
{ name: 'Carl', mail: 'Class A2' },
{ name: 'Daniel', mail: 'Class B2' },
{ name: 'Emi', mail: 'Class A3' },
{ name: 'Flank', mail: 'Class B3' },
{ name: 'George', mail: 'Class C4' },
{ name: 'Harry', mail: 'Class C5' }
];
I have select option element:
<ol class = "nya-bs-select" ng-model = "myModel">
<li nya-bs-option="person in myController.arrayCollection">
<a>
{{ person.name }}
</a>
</li>
</ol>
And second one is "textarea" :
<textarea ng-model="myModel2">
... ?
</textarea >
I would like to achieve this :
When I change "myModel" by choosing another person name from the first select option -> I want to set appropiate "mail" in the textarea.
Ex. when I choose "Alice" -> I would like to display "Class A" in the textarea. Moreover, when I multiselect "Alice", "Bob" -> I would like to display "Class A, Class B1"
Could you be so kind and help me How to achieve this ? (Multiselect is done by "nya-select" plugin -> so this is ok. I do not know how to display "mail" value from arrayCollection on the basis of name...
I am not familiar with the plugin you are using, however, I have tried to achieve what you wanted using multiple attribute of select element.
<select multiple="multiple" ng-model="selectedValues">
<option ng-repeat="mail in a" value="{{mail.name}}">{{mail.mail}}</option>
</select>
<textarea>{{selectedValues}}</textarea>
Please review the plunker at "http://plnkr.co/edit/u2sXnMkYSEYshAcLgyn7?p=preview"
Answer updated as per the comments below. OP is asking for a generic element to be reused on the page. There are possibly other/easier ways to do this, but I am extending the previous answer.
Set value attribute in each list element to person (this is needed for regular multi-select list, although may not be needed for nya-select):
<li nya-bs-option="person in myController.arrayCollection" value="{{person}}">
The ng-model myModel in the ordered list should contain the selections. We'll use that to render the content in the textarea. Add the following directive to the application:
myApp.directive('txtArea', function() {
return {
restrict: 'E',
replace: 'true',
scope: {data: '=', property: '#'},
template: "<textarea readonly>{{result()}}</textarea>",
link: function(scope, elem, attrs) {
scope.result = function() {
var ret = "";
angular.forEach(scope.data, function(value, key) {
var suff = (key === scope.data.length - 1) ? '' : ', ';
ret += JSON.parse(value)[scope.property] + suff;
});
return ret;
}
}
};
});
The directive is generic and can be reused across controllers. This also adds a comma after each intermediary value. Now replace the textarea element with:
<txt-area data="myModel" property="mail"></txt-area>
myModel is the model bound to the ordered list and mail is the property to use in the directive/filter.
Working jsfiddle with regular multi-select list.
Latest updated jsfiddle based on discussion below.

Angular ng-repeat with constant & Restangular

I'm working with a weird data model (no way around it at this point). I'm using restangular to make a rest call to get back a single resource object
Normally, the resource object returned by restangular is just whatever I set my
$scope.resource = response to and I can do resource.name , resource.id in the view/template, etc..
Except this group of resources instead of returning the key, value pairs in the response object, it returns an object within an object like so
resource1: {name: 'value', stuff: 'value', etc}
which is fine because then I would just set my $scope.resource = response.resource1 in my controller
except the problem is, is that there's 5 different kind of resource object names so if I make a resource by id call I might get back resource2, resource4, resource1, etc. so setting my $scope.resource = response.resource1 would only work when I get resource1.
My first attempt to solve this was to just use ng-repeat in which I set
<ul ng-repeat="(resource, value) in resource">
<li class="list-group-item">
Name:
<span class="pull-right"> {{ resource.name }} </span>
</li>
</ul>
which works great except because restangular returns all this extra stuff it's looping through each object it's repeating a bunch of blank html stuff if that makes sense.
My other thought was to try making a constant and make an object that has all 5 resources there and my ng-repeat would only populate based off that constant object (ie: it would check for those strings "resource1, resource2, etc" and if it's there then it will populate the template. But I'm not exactly sure how to do this.
Any other options or are there ng-repeat features i'm just not utilizing? any Help thanks
Here's the example I will be working from. Initially your incoming data looks something like this I believe...
$scope.data = [
{
resource1 : { name: 'r1' }
},
{
resource2 : { name: 'r2' }
},
{
resource2 : { name: 'r2' }
}];
When you receive the data you can normalize it by flattening it out into the following structure...
$scope.normalized = [
{ name : 'r1' },
{ name : 'r2' },
{ name : 'r2' }
];
Or you can add a common field for the object "type"
$scope.expanded = [
{
type : 'resource1',
resource1 : { name: 'r1' }
},
{
type : 'resource2',
resource2 : { name: 'r2' }
},
{
type : 'resource2',
resource2 : { name: 'r2' }
}];
Or you can normalize but retain type data...
$scope.normalizedType = [
{ type : 'resource1', name : 'r1' },
{ type : 'resource2', name : 'r2' },
{ type : 'resource2', name : 'r2' }
];
Normalizing upon retrieval of the data is probably your best bet. The question then becomes do you need to retain the objects type information.
So another solution I came up with was put all the resource key names into a list
resources = ['resource1', 'resource2', 'resource3', 'etc..']
and in my restangular service promise I just checked for which resource number it would be with a for loop like this
return ResourceRestangular.all('resource').get(resourceId).then(function(response){
for (i = 0; i < resources.length ; i++){
if (resources[i] in response){
self.resource = response[resources[i]];
}
}
return self.resource;
No need for ng-repeat anymore!

Add element to navigation property breezejs entity

Well, I'm fairly new to both angular and breeze and I have an entity called Collection with a navigation property products since a collection can have many products in it.
So when I click a button I want to add that product to that collection but I haven't had any luck with it, I read breeze.js documentation and apparently doing something like
collection.products.push(product)
should work, but it's not working any thoughts on this?
this is the entity definition
addType({
name: 'Collection',
defaultResourceName: 'collections',
dataProperties: {
id: { type: ID },
name: { max: 255, null: false },
slug: { max: 255 },
productsCount: { type: DT.Int16 }
},
navigationProperties: {
products: {
type: 'Product',
hasmany: true
}
}
})
This is the code that actually tries to add the item to the products
function addToCollection(product){
logSuccess('Product added to collection');
//trying to put a product into the collection products, with no luck
vm.collection.products.push(product);
}
And this is the template where the products are listed and the user can add them to the collection.
tbody
tr(ng-repeat="product in vm.products | inCollection:vm.filter_by")
td {{ product.master.sku }}
td {{ product.name }}
td {{ product.price | currency }}
td
img(data-ng-src="{{ product.master.images[0].mini_url }}")
td.text-center
.btn-group.btn-group-xs
a.btn.btn-default(data-ng-click="vm.addToCollection(product)")
i.fa.fa-plus
.btn-group.btn-group-xs
a.btn.btn-default(data-ng-click="vm.removeFromCollection(product)")
i.fa.fa-minus
I've been debugging and breeze is not returning any goodAdds so it won't add it to the collection, any ideas on why this is not a goodAdd? BTW, collections N -> N products.
As far as I know breeze doesn't support modification through Navigation properties So what you need to have is 2 types .. Collection and Property..
addType({
name: 'Proeprty',
defaultResourceName: 'properties',
dataProperties: {
id: { type: ID },
collectionId: { type: int32}
},
navigationProperties: {
collection: {
type: 'Collection',
isScalar: true
}
}
})
then when you want to add onto it you just make sure you set the collectionId
Breeze's Navigation Properties aren't like typical relationships

Resources