We are migrating from CRM 2011 to CRM 2013, both on-premise version. We have a ribbon customization on the Case form using javascript that loads up a custom Lookup view of N:N associated Account entity. From this custom lookup view, users can associate the selected Account records with the current Case.
For some reason this function is not working anymore in crm 2013. The custom Lookup view is still loaded up correctly, however for some reason the Account records are not getting associated with the parent Case record anymore.
I read another question about this which was resolved using the link below by Paul Nieuwelaar:
http://www.magnetismsolutions.co.nz/blog/paulnieuwelaar/2014/04/21/filter-n-n-add-existing-lookup-dynamics-crm-2013
Basically the ‘LookupObjects’ function is not working anymore in CRM 2013 and must be replace by ‘LookupObjectsWithCallback’.
However even after following this solution I'm still not able to associate the Account records to the Case. Here is my code below that I have modified to follow Paul Nieuwelaar's suggestion. Am I missing something here? I even included in the code if the CRM 2011 version is still using Rollup 12, just in case. I have a feeling this is probably because the parent Case was not picked up properly in the script.
Thanks, any help is greatly appreciated.
-elisabeth
function openAddLookupDialog(gridTypeCode) {
var relName = "new_account_incident";
var roleOrd = 2;
var viewId = "{00000000-0000-0000-00AA-000010001002}"; //dummy view ID
if (!IsNull(relName)) {
var customView = {
fetchXml: "{...}", //my FetchXML
id: viewId,
layoutXml: "{...}", //my layoutXml
name: "Filtered Lookup View",
recordType: gridTypeCode,
Type: 0
};
var parent = GetParentObject(null, 0);
var parameters = [gridTypeCode, "", relName, roleOrd, parent];
var callbackRef = Mscrm.Utilities.createCallbackFunctionObject("locAssocObjAction", this, parameters, false);
//pops the lookup window with our view injected
var lookupItems = LookupObjectsWithCallback(callbackRef, null, "multi", gridTypeCode, 0, null, "", null, null, null, null, null, null, viewId, [customView]);
}
if (lookupItems && lookupItems.items.length > 0) {
//beginning of rollup 12 must make modification
var parentId;
var parentTypeCode;
if (typeof (GetParentObject) == "function") { //post rollup 12 has its own function to get this
var parent = GetParentObject();
parentId = parent.id;
parentTypeCode = parent.objectTypeCode;
}
else { //pre rollup 12 still needs to use the old way
var parent = typeof (crmFormSubmit) == "undefined" ? $get("crmFormSubmit") : crmFormSubmit;
//according to daniels blog crmFormSubmit should already be defined, but it's not...
if (parent) {
parentId = parent.crmFormSubmitId.value;
parentTypeCode = parent.crmFormSubmitObjectType.value;
}
else {
parentId = window.parent.crmFormSubmit.crmFormSubmitId.value;
parentTypeCode = window.parent.crmFormSubmit.crmFormSubmitObjectType.value;
}
}//end of rollup 12 modification
//both of AssociateObjects that I try below here don't work
//AssociateObjects(crmFormSubmit.crmFormSubmitObjectType.value, crmFormSubmit.crmFormSubmitId.value, gridTypeCode, lookupItems, IsNull(roleOrd) || roleOrd == 2, "", relName);
AssociateObjects(parentTypeCode, parentId, gridTypeCode, lookupItems, IsNull(roleOrd) || roleOrd == 2, "", relName);
}
}
We also modified the customization.xml file to that triggers the javascript when the button is clicked.
<CommandDefinition Id="new.Form.incident.MainTab.Actions.AddExistingProperties.Command">
<EnableRules>
<EnableRule Id="new.Form.incident.MainTab.Actions.AddExistingProperties.Command.EnableRule.FormStateRule" />
<EnableRule Id="new.Form.incident.MainTab.Actions.AddExistingProperties.Command.EnableRule.ValueRule" />
</EnableRules>
<DisplayRules />
<Actions>
<JavaScriptFunction FunctionName="openAddLookupDialog" Library="$webresource:new_account_incident.js">
<IntParameter Value="1" />
</JavaScriptFunction>
</Actions>
Fyi this code above is WORKING! What's not working is some portion of the code that's supposed to refresh the subgrid... still troubleshooting
Related
In my custom module, there is one relation field. After click on create and edit form view is pop up. But I didn’t want to open this form view as a popup. I want to open this form view in the current window or in the current form. This is possible in odoo 12 or by using javascript Please, anyone, help me.
Thanks in advance.
Edit
Model and view are defined as per odoo instruction as :
class SurveySurvey(models.Model):
_name = 'survey.survey'
pages_ids = fields.One2many('survey.page','survey_id', string='Pages', copy=True)
View:
<field name="pages_ids" mode="tree" context="{'default_survey_id': active_id}" options="{'no_open':False}">
<tree editable="bottom" >
<field name="title"/>
<field name="question_ids" class="question_ids_class" widget="many2many_tags" context="{'page_id': active_id}" domain="[('page_id','=','active_id')]" options="{'no_open':true,'no_quick_create':true}"/>
</tree>
</field>
question_id is a relation field after click on create and edit option available in relation field one popup is open javascript code for that pop is as follows:
_searchCreatePopup: function (view, ids, context) {
var self = this;
return new dialogs.SelectCreateDialog(this, _.extend({}, this.nodeOptions, {
res_model: this.field.relation,
domain: this.record.getDomain({fieldName: this.name}),
context: _.extend({}, this.record.getContext(this.recordParams), context || {}),
title: (view === 'search' ? _t("Search: ") : _t("Create: ")) + this.string,
initial_ids: ids ? _.map(ids, function (x) { return x[0]; }) : undefined,
initial_view: view,
disable_multiple_selection: true,
no_create: !self.can_create,
on_selected: function (records) {
self.reinitialize(records[0]);
self.activate();
}
})).open();
},
The above code is available in web/static/js/fields/relational_fields.js
For better understanding please see screenshots.
Screenshot after click on Create and edit
I'm trying to change the display format on the DatePicker/TimePicker used by the sap.m.P13nItem when the selected column type is date/time.
I have tried changing the aggregation P13nItem from the P13nFilterPanel in order to include the property formatSettings, but it didn't work.
Here is a sample of my XML view code.
<P13nFilterPanel id="filterPanel" visible="true" type="filter" containerQuery="true" items="{
path: 'SchedulingFilter>/ColumnCollectionFilter'
}" filterItems="{
path: 'SchedulingFilter>/FilterItems'
}">
<P13nItem columnKey="{SchedulingFilter>columnKey}" text="{SchedulingFilter>label}" type="{SchedulingFilter>type}" maxLength="{SchedulingFilter>maxLength}" formatSettings="{SchedulingFilter>formatSettings>" />
<filterItems>
<P13nFilterItem columnKey="{SchedulingFilter>keyField}" operation="{SchedulingFilter>operation}" value1="{SchedulingFilter>value1}" value2="{SchedulingFilter>value2}" exclude="{SchedulingFilter>exclude}" />
</filterItems>
</P13nFilterPanel>
Here is an extract of how I'm filling the bound data.
$.each(columnsKeys, function (i, item) {
const columnData = {};
const columnDescriptionItem = columnDescription[item];
columnData.columnKey = item;
columnData.text = columnDescriptionItem.label;
columnData.type = columnDescriptionItem.type;
columnData.formatSettings = {
pattern: 'yyyy/MM/dd',
UTC: false
};
columnData.maxLength = columnDescriptionItem.maxLength;
columnData.visible = columnDescriptionItem.visible;
columnData.index = columnDescriptionItem.index;
columnData.isEditable = columnDescriptionItem.isEditable;
columnData.isFilter = columnDescriptionItem.isFilter;
columnData.isSorter = columnDescriptionItem.isSorter;
columnsData.push(columnData);
});
The default behavior of the control displays the time/date fields as:
https://ibb.co/JcJJZhJ.
Edit: I discovered that the default behavior is based on the user's locale. I'm not considering the user's locale to change the display format on the others parts of my application.
I want to achieve, for example, the display formats "yyyy/MM/dd" and "hh:mm:ss" on these fields.
I had to extend the P13nConditionPanel (this one is responsible for the time/date components instantiation) and the P13nFilterPanel (it creates the P13nConditionPanel) on version 1.44.6 of SAPUI5 in order to solve this problem. I only had to add the necessary parameters to the DatePicker and TimePicker constructors (as shown below).
case "date":
oConditionGrid.oFormatter = sap.ui.core.format.DateFormat.getDateInstance();
params.displayFormat = DateFormatter.displayFormat();
oControl = new sap.m.DatePicker(params);
break;
case "time":
oConditionGrid.oFormatter = sap.ui.core.format.DateFormat.getTimeInstance();
params.displayFormat = TimeFormatter.getDisplayFormat();
oControl = new sap.m.TimePicker(params);
I posted my customized extended components code on pastebin:
Customized P13nConditionPanel
Customized P13nFilterPanel
I will later open an enhancement request on openui5 Github.
I have a Kendo.MVC project. The view has a model with a field of type List<>. I want to populate the List from a Javascript function. I've tried several ways, but can't get it working. Can someone explain what I'm doing wrong?
So here is my model:
public class Dashboard
{
public List<Note> ListNotes { get; set; }
}
I use the ListNotes on the view like this:
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
}
This works if I populate Model.ListNotes in the controller when the view starts...
public ActionResult DashBoard(string xsr, string vst)
{
var notes = rep.GetNotesByCompanyID(user.ResID, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
Dashboard employee = new Dashboard
{
ResID = intUser,
Type = intType,
FirstName = user.FirstName,
LastName = user.LastName,
ListNotes = listNotes
};
return View(employee);
}
... but I need to populate ListNotes in a Javascript after a user action.
Here is my javascript to make an ajax call to populate ListNotes:
function getReminders(e)
{
var userID = '#ViewBag.CurrUser';
$.ajax({
url: "/api/WoApi/GetReminders/" + userID,
dataType: "json",
type: "GET",
success: function (notes)
{
// Need to assign notes to Model.ListNotes here
}
});
}
Here's the method it calls with the ajax call. I've confirmed ListNotes does have the values I want; it is not empty.
public List<Koorsen.Models.Note> GetReminders(int id)
{
var notes = rep.GetNotesByCompanyID(id, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
foreach (Koorsen.OpenAccess.Note note in notes)
{
Koorsen.Models.Note newNote = new Koorsen.Models.Note()
{
NoteID = note.NoteID,
CompanyID = note.CompanyID,
LocationID = note.LocationID,
NoteText = note.NoteText,
NoteType = note.NoteType,
InternalNote = note.InternalNote,
NoteDate = note.NoteDate,
Active = note.Active,
AddBy = note.AddBy,
AddDate = note.AddDate,
ModBy = note.ModBy,
ModDate = note.ModDate
};
listNotes.Add(newNote);
}
return listNotes;
}
If ListNotes was a string, I would have added a hidden field and populated it in Javascript. But that didn't work for ListNotes. I didn't get an error, but the text on the screen didn't change.
#Html.HiddenFor(x => x.ListNotes)
...
...
$("#ListNotes").val(notes);
I also tried
#Model.ListNotes = notes; // This threw an unterminated template literal error
document.getElementById('ListNotes').value = notes;
I've even tried refreshing the page after assigning the value:
window.location.reload();
and refreshing the panel bar the code is in
var panelBar = $("#IntroPanelBar").data("kendoPanelBar");
panelBar.reload();
Can someone explain how to get this to work?
I don't know if this will cloud the issue, but the reason I need to populate the model in javascript with an ajax call is because Model.ListNotes is being used in a Kendo Panel Bar control and I don't want Model.ListNotes to have a value until the user expands the panel bar.
Here's the code for the panel bar:
#{
#(Html.Kendo().PanelBar().Name("IntroPanelBar")
.Items(items =>
{
items
.Add()
.Text("View Important Notes and Messages")
.Expanded(false)
.Content(
#<text>
#RenderReminders()
</text>
);
}
)
.Events(e => e
.Expand("getReminders")
)
)
}
Here's the helper than renders the contents:
#helper RenderReminders()
{
if (Model.ListNotes.Count <= 0)
{
#Html.Raw("No Current Messages");
}
else
{
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
<br />
}
}
}
The panel bar and the helpers work fine if I populate Model.ListNotes in the controller and pass Model to the view. I just can't get it to populate in the javascript after the user expands the panel bar.
Perhaps this will do it for you. I will provide a small working example I believe you can easily extend to meet your needs. I would recommend writing the html by hand instead of using the helper methods such as #html.raw since #html.raw is just a tool to generate html in the end anyways. You can write html manually accomplish what the helper methods do anyway and I think it will be easier for you in this situation. If you write the html correctly it should bind to the model correctly (which means it won't be empty on your post request model) So if you modify that html using javascript correctly, it will bind to your model correctly as well.
Take a look at some of these examples to get a better idea of what I am talking about:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
So to answer your question...
You could build a hidden container to hold your list values like this (make sure this container is inside the form):
<div id="ListValues" style="display:none">
</div>
Then put the results your ajax post into a javascript variable (not shown).
Then in javascript do something like this:
$('form').off('submit'); //i do this to prevent duplicate bindings depending on how this page may be rendered futuristically as a safety precaution.
$('form').on('submit', function (e) { //on submit, modify the form data to include the information you want inside of your ListNotes
var data = getAjaxResults(); //data represents your ajax results. You can acquire and format that how you'd like I will use the following as an example format for how you could save the results as JSON data: [{NoteID ="1",CompanyID ="2"}]
let listLength = data.length;
for (let i = 0; i < listLength; i++) {
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].NoteID " value="' + data.NoteID +'" />')
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].CompanyID " value="' + data.CompanyID +'" />')
//for your ajax results, do this for each field on the note object
}
})
That should do it! After you submit your form, it should automatically model bind to you ListNotes! You will be able to inpsect this in your debugger on your post controller action.
I'm using an angular library that's called mdDataTable to handle my tables with searching, paging and so on.
I am trying to reproduce the functionality from the "Ajax Search Support" demo on this demo page, but I can't get it to work. Searching works fine, but my paging will only show that one page is avalible even if the results is eleven items and my pageSize is set to 5 per page.
I'm not sure how to simulate an api-call on codepen so I'll paste the code.
I also depend on Angular material and $resource. $resource is my "dataService" and then I have a service called paginationHandler, that's really just picks up pagination information in the response headers from the server (Custom header) and stores it for the application to use. I got an interceptor that handles storing that data.
My view containing the table:
<md-card class="bg-white" layout-fill md-whiteframe="4db">
<md-input-container class="padder-md m-t-xl">
<label style="padding-left: 20px; padding-right: 20px;">Sök användare</label>
<input type="text" ng-model="filterText">
</md-input-container>
<mdt-table paginated-rows="{isEnabled: true, rowsPerPageValues: [5,10,20,50,100]}"
mdt-row-paginator="vm.paginatorCallback(page, pageSize)"
sortable-columns="true"
animate-sort-icon="true"
mdt-row-paginator-no-results-message="Inga resultat hittades..."
mdt-row-paginator-error-message="Fel uppstod vid hämtning av maskinmodeller."
mdt-trigger-request="vm.getLoadResultsCallback(loadPageCallback)"
mdt-row="{
'table-row-id-key': 'id',
'column-keys': [
'name',
'category',
'machineModelType.name',
'createdDate',
'remove'
],
}">
<mdt-header-row>
<mdt-column align-rule="left">Namn</mdt-column>
<mdt-column align-rule="left">Kategori</mdt-column>
<mdt-column align-rule="left">Typ</mdt-column>
<mdt-column align-rule="left">Skapad</mdt-column>
<mdt-column align-rule="left">Ta bort</mdt-column>
</mdt-header-row>
</mdt-table>
</md-card>
And this is my controller. It's a route in ui-router that has the controller defined in that route "as vm", so I haven't forgotten to link the controller to the view.
(function () {
"use strict";
angular.module("app")
.controller("detailsManufacturerCtrl", [
"$stateParams",
"dataService",
"$scope",
"paginationHandler",
function ($stateParams, dataService, $scope, paginationHandler) {
var vm = this;
vm.machineModels = [];
// Data retrieval
vm.getMachineModels = function(){
dataService.manufacturerMachineModels.query({manufacturerId: $stateParams.id, sort: "name", page: 1, pageSize: 5, search: ""}, function(response){
vm.machineModels = response;
vm.pagination = paginationHandler.get();
});
};
// Machine Model Table Functions
vm.paginatorCallback = function(page, pageSize){
var query = $scope.filterText ? $scope.filterText : '';
return uow.manufacturerMachineModels.query({
manufacturerId: $stateParams.id,
sort: "name",
page: page,
pageSize: pageSize,
search: query
}).$promise.then(function(result){
return {
results: result,
totalResultCount: result.length
}
});
};
var loadPageCallbackWithDebounce;
$scope.$watch('filterText', function(){
if(loadPageCallbackWithDebounce){
loadPageCallbackWithDebounce();
}
});
vm.getLoadResultsCallback = function(loadPageCallback){
loadPageCallbackWithDebounce = _.debounce(loadPageCallback, 500);
};
// INIT
vm.getMachineModels();
}
])
}());
It's close to the demo except for the item properties and the dataservice is my own ofc.
This is where my ajax-call ends up. I use ASP.NET Web Api 2 as server.
[Route("", Name = "ManufacturerMachineModelList")]
public async Task<IHttpActionResult> Get(int manufacturerId, // Url values
// Filtering (None)
string sort = "name", // Sorting
int page = 1, int pageSize = 5, //Pagination
string search = "") // Search
{
try
{
var manufacturer = Uow.Manufacturer.GetById(manufacturerId);
// Not Found
if (manufacturer == null) { return NotFound(); }
var machineModels = Uow.MachineModel.GetAll(sort, search)
// Url filter
.Where(mm => mm.ManufacturerId == manufacturerId)
// Query filters (None)
.ToList();
// Pagination
var paginationHeader = GetPaginationHeader(machineModels, pageSize, page, sort);
HttpContext.Current.Response.Headers.Add("Pagination", JsonConvert.SerializeObject(paginationHeader));
// Return list and add pagination
return Ok(machineModels
.Skip(pageSize * (page - 1))
.Take(pageSize)
.ToList());
}
catch (Exception exc)
{
return InternalServerError(exc);
}
}
The "GetPaginationHeader()" method returns a anonymous object that looks like this:
var object = new
{
currentPage = page,
pageSize = pageSize,
totalCount = totalCount,
totalPages = totalPages,
previousPageLink = prevLink,
nextPageLink = nextLink
}
Which I then add as a header that's exposed through CORS.
These values are always correct.
The thing is that I'm not really sure what to do with these values, if anything. At the moment I just store the values when the response that includes "Pagination" header comes back and nothing more.
When I make this call I get 11 results back, and the table shows the correct pageSize (5), but not the correct amount of pages (always 1, should be 3), so I only see the first five results.
So, finally, my question is, which values in the ajax search demo should I change to my own values? If none, what else am I doing wrong?
I'm totally stuck so any help is appriciated!
EDIT: I've been trying to get the demo working locally but without luck. If someone can help me get that to work, then I can debug the example and see where I go wrong.
I am trying to create a small chat app to help me learn AngularFire (Firebase + AngularJS). The only functionality i am trying to get is the ability to create chat rooms and then the ability to chat in each room. By the way, i'm doing this in Rails if it matters (my user login and everything is handled through Rails).
So far i have this as my sample code, this is what the view looks like:
<div ng-controller="RoomsCtrl">
<div ng-repeat="rm in rooms">
<div>
<ul>
<li class="message phm pvm pull-left" ng-repeat="msg in messages">
<span class="message-author">{{msg.from}}</span>
<span class="message-body">{{msg.body}}</span>
<span class="message-timestamp">{{msg.timestamp | date:'MMM d, yyyy h:mm a'}}</span>
</li>
</ul>
</div>
<form>
<span class="hidden"><%= current_user.full_name %></span>
<textarea ng-model="msgBody" ng-keydown="addMessage($event)" placeholder="What's on your mind..."></textarea>
</form>
</div>
<form>
<input type="text" ng-model="roomName" ng-keydown="addRoom($event)" placeholder="Enter a room name..."><
</form>
</div>
Here is my AngularFire script:
var app = angular.module("ChatApp", ["firebase"]);
function RoomsCtrl($scope, $firebase) {
var organizationId;
if (gon) {
organizationId = gon.organization_id;
}
var orgRef = new Firebase("https://glowing-fire-7051.firebaseio.com/"+organizationId);
$scope.rooms = $firebase(orgRef);
$scope.addRoom = function(e) {
if (e.keyCode != 13) return;
$scope.rooms.$add({name: $scope.roomName, timestamp: new Date().getTime()})
$scope.roomName = "";
e.preventDefault();
}
$scope.messages = $firebase(orgRef);
$scope.addMessage = function(e) {
if (e.keyCode != 13) return;
$scope.messages.$add({name: $scope.msgName, body: $scope.msgBody, timestamp: new Date().getTime()})
$scope.msgBody = "";
e.preventDefault();
}
}
Each user belongs_to and Organization as you can see by the gon part that is just getting the id of the organization that the current_user belongs to. The code i have for the addRoom does actually create a room under the organization. The Forge data looks like this:
<my forge id>
1
JHiiMka5OloVaqf-sA7
name: "Test Room"
timestamp: 1394500795299
JHjA0rwIDJNVDU4HVaF
name: "Another Room"
timestamp: 1394508307247
I am also seeing the data being reflected on the site as well. When i create a new room, the room displays on the site. My problem (i think) lies only with the messages. I have been researching for hours with little to no success on a the subject of nested references. I kind of understand it but i haven't been able to figure out how i can create a room (dynamically through the site) and then have access to create messages under that room's node in Firebase.
My view code above shows you how i was thinking it would display on the page. My question is, how do i tie the two together through Firebase / AngularFire? Thanks in advance for any help! And let me know if you have any questions that might shed more light on anything.
UPDATE:
I sent this question to Firebase support through their website and received a response helping me with almost all of it. I sent a follow up email to get clarification on a section i'm not understanding in their response and waiting to here back. Their advice was to replace:
var orgRef = new Firebase("https://glowing-fire-7051.firebaseio.com/"+organizationId);
with
var orgRef = new Firebase("https://glowing-fire-7051.firebaseio.com/").child(organizationId);
That would create a new Firebase reference for a child of an existing location. Then they said to use this for my $scope.messages definition:
$scope.messages = $firebase(orgRef.child(roomID).child("messages"));
This would assume that in /1/room/ there is a child named “messages” which holds your messages.
The part i am having trouble with is the .child(roomID) in the messages definition because it is telling me it is undefined (which it is). What should that be defined as...i'm assuming it should be the ID of the newly created room?
I finally got the answer to my question from posting on the Firebase + AngularJS google group. I was missing a couple things. Here is my final code:
var app = angular.module("ChatApp", ["firebase"]);
function RoomsCtrl($scope, $firebase) {
var organizationId;
if (gon) {
organizationId = gon.organization_id;
}
var orgRef = new Firebase("https://<my forge id>.firebaseio.com/").child(organizationId);
$scope.rooms = $firebase(orgRef.child('rooms'));
$scope.addRoom = function(e) {
if (e.keyCode != 13) return;
$scope.rooms.$add({name: $scope.roomName, timestamp: new Date().getTime()}).then(function(ref){
var roomId = ref.name();
$scope.messages = $firebase(orgRef.child('rooms').child(roomId).child("messages"));
});
$scope.roomName = "";
e.preventDefault();
}
$scope.addMessage = function(e) {
if (e.keyCode != 13) return;
$scope.messages.$add({name: $scope.msgName, body: $scope.msgBody, timestamp: new Date().getTime()})
$scope.msgBody = "";
e.preventDefault();
}
}
The main parts that i was missing was the .then() callback and i wasn't setting up the definition to $scope.messages correctly where it would be referencing the parent room. These lines are the major part of the fix:
$scope.rooms.$add({name: $scope.roomName, timestamp: new Date().getTime()}).then(function(ref){
var roomId = ref.name();
$scope.messages = $firebase(orgRef.child('rooms').child(roomId).child("messages"));
});
Hope this helps anyone else with a similar problem.